diff --git a/js/src/dropdown/dropdown.js b/js/src/dropdown/dropdown.js index 2c30ba740a..26bcf2aa3a 100644 --- a/js/src/dropdown/dropdown.js +++ b/js/src/dropdown/dropdown.js @@ -83,7 +83,8 @@ const Default = { flip: true, boundary: 'scrollParent', reference: 'toggle', - display: 'dynamic' + display: 'dynamic', + popperConfig: null } const DefaultType = { @@ -91,7 +92,8 @@ const DefaultType = { flip: 'boolean', boundary: '(string|element)', reference: '(string|element)', - display: 'string' + display: 'string', + popperConfig: '(null|object)' } /** @@ -339,7 +341,7 @@ class Dropdown { } _getPopperConfig() { - const popperConfig = { + let popperConfig = { placement: this._getPlacement(), modifiers: { offset: this._getOffset(), @@ -359,6 +361,13 @@ class Dropdown { } } + if (this._config.popperConfig) { + popperConfig = { + ...popperConfig, + ...this._config.popperConfig + } + } + return popperConfig } diff --git a/js/src/dropdown/dropdown.spec.js b/js/src/dropdown/dropdown.spec.js index 92d8fea033..e99e992f3d 100644 --- a/js/src/dropdown/dropdown.spec.js +++ b/js/src/dropdown/dropdown.spec.js @@ -99,6 +99,28 @@ describe('Dropdown', () => { expect(dropdown.toggle).toHaveBeenCalled() }) + + it('should allow to pass config to popper.js thanks to popperConfig', () => { + fixtureEl.innerHTML = [ + '' + ].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', () => { diff --git a/js/src/tooltip/tooltip.js b/js/src/tooltip/tooltip.js index 33f0173a3f..8bf998468c 100644 --- a/js/src/tooltip/tooltip.js +++ b/js/src/tooltip/tooltip.js @@ -56,7 +56,8 @@ const DefaultType = { boundary: '(string|element)', sanitize: 'boolean', sanitizeFn: '(null|function)', - whiteList: 'object' + whiteList: 'object', + popperConfig: '(null|object)' } const AttachmentMap = { @@ -84,7 +85,8 @@ const Default = { boundary: 'scrollParent', sanitize: true, sanitizeFn: null, - whiteList: DefaultWhitelist + whiteList: DefaultWhitelist, + popperConfig: null } const HoverState = { @@ -129,10 +131,6 @@ const Trigger = { class Tooltip { constructor(element, config) { - /** - * Check for Popper dependency - * Popper - https://popper.js.org - */ if (typeof Popper === 'undefined') { throw new TypeError('Bootstrap\'s tooltips require Popper.js (https://popper.js.org)') } @@ -247,7 +245,7 @@ class Tooltip { this._timeout = null this._hoverState = null this._activeTrigger = null - if (this._popper !== null) { + if (this._popper) { this._popper.destroy() } @@ -301,27 +299,7 @@ class Tooltip { EventHandler.trigger(this.element, this.constructor.Event.INSERTED) - this._popper = new Popper(this.element, tip, { - 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) - }) + this._popper = new Popper(this.element, tip, this._getPopperConfig(attachment)) tip.classList.add(ClassName.SHOW) @@ -482,6 +460,40 @@ class Tooltip { // 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) { this.getTipElement().classList.add(`${CLASS_PREFIX}-${attachment}`) } diff --git a/js/src/tooltip/tooltip.spec.js b/js/src/tooltip/tooltip.spec.js index 1e858d369a..e4bddcf003 100644 --- a/js/src/tooltip/tooltip.spec.js +++ b/js/src/tooltip/tooltip.spec.js @@ -108,6 +108,21 @@ describe('Tooltip', () => { tooltipInContainerEl.click() }) + + it('should allow to pass config to popper.js thanks to popperConfig', () => { + fixtureEl.innerHTML = '' + + 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', () => { diff --git a/site/content/docs/4.3/components/dropdowns.md b/site/content/docs/4.3/components/dropdowns.md index 42bc1bb56c..6d0f094b57 100644 --- a/site/content/docs/4.3/components/dropdowns.md +++ b/site/content/docs/4.3/components/dropdowns.md @@ -855,6 +855,12 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap 'dynamic' By default, we use Popper.js for dynamic positioning. Disable this with static. + + popperConfig + null | object + null + To change Bootstrap default Popper.js config, see Popper.js configuration + diff --git a/site/content/docs/4.3/components/popovers.md b/site/content/docs/4.3/components/popovers.md index dfd4904e06..04ba2f15ce 100644 --- a/site/content/docs/4.3/components/popovers.md +++ b/site/content/docs/4.3/components/popovers.md @@ -281,6 +281,12 @@ Note that for security reasons the `sanitize`, `sanitizeFn` and `whiteList` opti null Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization. + + popperConfig + null | object + null + To change Bootstrap default Popper.js config, see Popper.js configuration + diff --git a/site/content/docs/4.3/components/tooltips.md b/site/content/docs/4.3/components/tooltips.md index 373cc45d52..880e761851 100644 --- a/site/content/docs/4.3/components/tooltips.md +++ b/site/content/docs/4.3/components/tooltips.md @@ -278,6 +278,12 @@ Note that for security reasons the `sanitize`, `sanitizeFn` and `whiteList` opti null Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization. + + popperConfig + null | object + null + To change Bootstrap default Popper.js config, see Popper.js configuration +