0
0
mirror of https://github.com/twbs/bootstrap.git synced 2025-01-30 22:52:24 +01:00

allow to pass popper.js configuration for tooltip/popover and dropdown

This commit is contained in:
Johann-S 2019-08-14 17:27:58 +02:00 committed by XhmikosR
parent b3cf60018c
commit f03c10a189
7 changed files with 107 additions and 31 deletions

View File

@ -83,7 +83,8 @@ const Default = {
flip: true, flip: true,
boundary: 'scrollParent', boundary: 'scrollParent',
reference: 'toggle', reference: 'toggle',
display: 'dynamic' display: 'dynamic',
popperConfig: null
} }
const DefaultType = { const DefaultType = {
@ -91,7 +92,8 @@ const DefaultType = {
flip: 'boolean', flip: 'boolean',
boundary: '(string|element)', boundary: '(string|element)',
reference: '(string|element)', reference: '(string|element)',
display: 'string' display: 'string',
popperConfig: '(null|object)'
} }
/** /**
@ -339,7 +341,7 @@ class Dropdown {
} }
_getPopperConfig() { _getPopperConfig() {
const popperConfig = { let popperConfig = {
placement: this._getPlacement(), placement: this._getPlacement(),
modifiers: { modifiers: {
offset: this._getOffset(), offset: this._getOffset(),
@ -359,6 +361,13 @@ class Dropdown {
} }
} }
if (this._config.popperConfig) {
popperConfig = {
...popperConfig,
...this._config.popperConfig
}
}
return popperConfig return popperConfig
} }

View File

@ -99,6 +99,28 @@ describe('Dropdown', () => {
expect(dropdown.toggle).toHaveBeenCalled() expect(dropdown.toggle).toHaveBeenCalled()
}) })
it('should allow to pass config to popper.js thanks to popperConfig', () => {
fixtureEl.innerHTML = [
'<div class="dropdown">',
' <button href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>',
' <div class="dropdown-menu">',
' <a class="dropdown-item" href="#">Secondary link</a>',
' </div>',
'</div>'
].join('')
const btnDropdown = fixtureEl.querySelector('[data-toggle="dropdown"]')
const dropdown = new Dropdown(btnDropdown, {
popperConfig: {
placement: 'left'
}
})
const popperConfig = dropdown._getPopperConfig()
expect(popperConfig.placement).toEqual('left')
})
}) })
describe('toggle', () => { describe('toggle', () => {

View File

@ -56,7 +56,8 @@ const DefaultType = {
boundary: '(string|element)', boundary: '(string|element)',
sanitize: 'boolean', sanitize: 'boolean',
sanitizeFn: '(null|function)', sanitizeFn: '(null|function)',
whiteList: 'object' whiteList: 'object',
popperConfig: '(null|object)'
} }
const AttachmentMap = { const AttachmentMap = {
@ -84,7 +85,8 @@ const Default = {
boundary: 'scrollParent', boundary: 'scrollParent',
sanitize: true, sanitize: true,
sanitizeFn: null, sanitizeFn: null,
whiteList: DefaultWhitelist whiteList: DefaultWhitelist,
popperConfig: null
} }
const HoverState = { const HoverState = {
@ -129,10 +131,6 @@ const Trigger = {
class Tooltip { class Tooltip {
constructor(element, config) { constructor(element, config) {
/**
* Check for Popper dependency
* Popper - https://popper.js.org
*/
if (typeof Popper === 'undefined') { if (typeof Popper === 'undefined') {
throw new TypeError('Bootstrap\'s tooltips require Popper.js (https://popper.js.org)') throw new TypeError('Bootstrap\'s tooltips require Popper.js (https://popper.js.org)')
} }
@ -247,7 +245,7 @@ class Tooltip {
this._timeout = null this._timeout = null
this._hoverState = null this._hoverState = null
this._activeTrigger = null this._activeTrigger = null
if (this._popper !== null) { if (this._popper) {
this._popper.destroy() this._popper.destroy()
} }
@ -301,27 +299,7 @@ class Tooltip {
EventHandler.trigger(this.element, this.constructor.Event.INSERTED) EventHandler.trigger(this.element, this.constructor.Event.INSERTED)
this._popper = new Popper(this.element, tip, { this._popper = new Popper(this.element, tip, this._getPopperConfig(attachment))
placement: attachment,
modifiers: {
offset: this._getOffset(),
flip: {
behavior: this.config.fallbackPlacement
},
arrow: {
element: `.${this.constructor.NAME}-arrow`
},
preventOverflow: {
boundariesElement: this.config.boundary
}
},
onCreate: data => {
if (data.originalPlacement !== data.placement) {
this._handlePopperPlacementChange(data)
}
},
onUpdate: data => this._handlePopperPlacementChange(data)
})
tip.classList.add(ClassName.SHOW) tip.classList.add(ClassName.SHOW)
@ -482,6 +460,40 @@ class Tooltip {
// Private // Private
_getPopperConfig(attachment) {
const defaultBsConfig = {
placement: attachment,
modifiers: {
offset: this._getOffset(),
flip: {
behavior: this.config.fallbackPlacement
},
arrow: {
element: `.${this.constructor.NAME}-arrow`
},
preventOverflow: {
boundariesElement: this.config.boundary
}
},
onCreate: data => {
if (data.originalPlacement !== data.placement) {
this._handlePopperPlacementChange(data)
}
},
onUpdate: data => this._handlePopperPlacementChange(data)
}
let resultConfig = defaultBsConfig
if (this.config.popperConfig) {
resultConfig = {
...defaultBsConfig,
...this.config.popperConfig
}
}
return resultConfig
}
_addAttachmentClass(attachment) { _addAttachmentClass(attachment) {
this.getTipElement().classList.add(`${CLASS_PREFIX}-${attachment}`) this.getTipElement().classList.add(`${CLASS_PREFIX}-${attachment}`)
} }

View File

@ -108,6 +108,21 @@ describe('Tooltip', () => {
tooltipInContainerEl.click() tooltipInContainerEl.click()
}) })
it('should allow to pass config to popper.js thanks to popperConfig', () => {
fixtureEl.innerHTML = '<a href="#" rel="tooltip"/>'
const tooltipEl = fixtureEl.querySelector('a')
const tooltip = new Tooltip(tooltipEl, {
popperConfig: {
placement: 'left'
}
})
const popperConfig = tooltip._getPopperConfig('top')
expect(popperConfig.placement).toEqual('left')
})
}) })
describe('enable', () => { describe('enable', () => {

View File

@ -855,6 +855,12 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap
<td>'dynamic'</td> <td>'dynamic'</td>
<td>By default, we use Popper.js for dynamic positioning. Disable this with <code>static</code>.</td> <td>By default, we use Popper.js for dynamic positioning. Disable this with <code>static</code>.</td>
</tr> </tr>
<tr>
<td>popperConfig</td>
<td>null | object</td>
<td>null</td>
<td>To change Bootstrap default Popper.js config, see <a href="https://popper.js.org/popper-documentation.html#Popper.Defaults">Popper.js configuration</a></td>
</tr>
</tbody> </tbody>
</table> </table>

View File

@ -281,6 +281,12 @@ Note that for security reasons the `sanitize`, `sanitizeFn` and `whiteList` opti
<td>null</td> <td>null</td>
<td>Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization.</td> <td>Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization.</td>
</tr> </tr>
<tr>
<td>popperConfig</td>
<td>null | object</td>
<td>null</td>
<td>To change Bootstrap default Popper.js config, see <a href="https://popper.js.org/popper-documentation.html#Popper.Defaults">Popper.js configuration</a></td>
</tr>
</tbody> </tbody>
</table> </table>

View File

@ -278,6 +278,12 @@ Note that for security reasons the `sanitize`, `sanitizeFn` and `whiteList` opti
<td>null</td> <td>null</td>
<td>Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization.</td> <td>Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization.</td>
</tr> </tr>
<tr>
<td>popperConfig</td>
<td>null | object</td>
<td>null</td>
<td>To change Bootstrap default Popper.js config, see <a href="https://popper.js.org/popper-documentation.html#Popper.Defaults">Popper.js configuration</a></td>
</tr>
</tbody> </tbody>
</table> </table>