mirror of
https://github.com/twbs/bootstrap.git
synced 2025-02-23 09:41:11 +00:00
Support Popper virtual elements (#32376)
Adds the ability to use objects implementing the virtual element interface as the value for the reference option of a dropdown config. Co-authored-by: XhmikosR <xhmikosr@gmail.com>
This commit is contained in:
parent
44667d89fa
commit
2d46e47464
@ -84,7 +84,7 @@ const DefaultType = {
|
|||||||
offset: '(number|string|function)',
|
offset: '(number|string|function)',
|
||||||
flip: 'boolean',
|
flip: 'boolean',
|
||||||
boundary: '(string|element)',
|
boundary: '(string|element)',
|
||||||
reference: '(string|element)',
|
reference: '(string|element|object)',
|
||||||
display: 'string',
|
display: 'string',
|
||||||
popperConfig: '(null|object)'
|
popperConfig: '(null|object)'
|
||||||
}
|
}
|
||||||
@ -172,6 +172,8 @@ class Dropdown extends BaseComponent {
|
|||||||
if (typeof this._config.reference.jquery !== 'undefined') {
|
if (typeof this._config.reference.jquery !== 'undefined') {
|
||||||
referenceElement = this._config.reference[0]
|
referenceElement = this._config.reference[0]
|
||||||
}
|
}
|
||||||
|
} else if (typeof this._config.reference === 'object') {
|
||||||
|
referenceElement = this._config.reference
|
||||||
}
|
}
|
||||||
|
|
||||||
this._popper = Popper.createPopper(referenceElement, this._menu, this._getPopperConfig())
|
this._popper = Popper.createPopper(referenceElement, this._menu, this._getPopperConfig())
|
||||||
@ -257,6 +259,13 @@ class Dropdown extends BaseComponent {
|
|||||||
|
|
||||||
typeCheckConfig(NAME, config, this.constructor.DefaultType)
|
typeCheckConfig(NAME, config, this.constructor.DefaultType)
|
||||||
|
|
||||||
|
if (typeof config.reference === 'object' && !isElement(config.reference) &&
|
||||||
|
typeof config.reference.getBoundingClientRect !== 'function'
|
||||||
|
) {
|
||||||
|
// Popper virtual elements require a getBoundingClientRect method
|
||||||
|
throw new Error(`${NAME}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`)
|
||||||
|
}
|
||||||
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,6 +367,58 @@ describe('Dropdown', () => {
|
|||||||
dropdown.toggle()
|
dropdown.toggle()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should toggle a dropdown with a valid virtual element reference', done => {
|
||||||
|
fixtureEl.innerHTML = [
|
||||||
|
'<div class="dropdown">',
|
||||||
|
' <button class="btn dropdown-toggle visually-hidden" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
|
||||||
|
' <div class="dropdown-menu">',
|
||||||
|
' <a class="dropdown-item" href="#">Secondary link</a>',
|
||||||
|
' </div>',
|
||||||
|
'</div>'
|
||||||
|
].join('')
|
||||||
|
|
||||||
|
const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
|
||||||
|
const virtualElement = {
|
||||||
|
getBoundingClientRect() {
|
||||||
|
return {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(() => new Dropdown(btnDropdown, {
|
||||||
|
reference: {}
|
||||||
|
})).toThrow()
|
||||||
|
|
||||||
|
expect(() => new Dropdown(btnDropdown, {
|
||||||
|
reference: {
|
||||||
|
getBoundingClientRect: 'not-a-function'
|
||||||
|
}
|
||||||
|
})).toThrow()
|
||||||
|
|
||||||
|
// use onFirstUpdate as Poppers internal update is executed async
|
||||||
|
const dropdown = new Dropdown(btnDropdown, {
|
||||||
|
reference: virtualElement,
|
||||||
|
popperConfig: {
|
||||||
|
onFirstUpdate() {
|
||||||
|
expect(virtualElement.getBoundingClientRect).toHaveBeenCalled()
|
||||||
|
expect(btnDropdown.classList.contains('show')).toEqual(true)
|
||||||
|
expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
spyOn(virtualElement, 'getBoundingClientRect').and.callThrough()
|
||||||
|
|
||||||
|
dropdown.toggle()
|
||||||
|
})
|
||||||
|
|
||||||
it('should not toggle a dropdown if the element is disabled', done => {
|
it('should not toggle a dropdown if the element is disabled', done => {
|
||||||
fixtureEl.innerHTML = [
|
fixtureEl.innerHTML = [
|
||||||
'<div class="dropdown">',
|
'<div class="dropdown">',
|
||||||
|
@ -886,9 +886,9 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>reference</code></td>
|
<td><code>reference</code></td>
|
||||||
<td>string | element</td>
|
<td>string | element | object</td>
|
||||||
<td><code>'toggle'</code></td>
|
<td><code>'toggle'</code></td>
|
||||||
<td>Reference element of the dropdown menu. Accepts the values of <code>'toggle'</code>, <code>'parent'</code>, or an HTMLElement reference. For more information refer to Popper's <a href="https://popper.js.org/docs/v2/constructors/#createpopper">constructor docs</a>.</td>
|
<td>Reference element of the dropdown menu. Accepts the values of <code>'toggle'</code>, <code>'parent'</code>, an HTMLElement reference or an object providing <code>getBoundingClientRect</code>. For more information refer to Popper's <a href="https://popper.js.org/docs/v2/constructors/#createpopper">constructor docs</a> and <a href="https://popper.js.org/docs/v2/virtual-elements/">virtual element docs</a>.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>display</code></td>
|
<td><code>display</code></td>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user