diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 366781b3e894..7af07734047e 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -32,7 +32,7 @@ const DefaultType = { html : 'boolean', selector : '(string|boolean)', placement : '(string|function)', - offset : '(number|string)', + offset : '(number|string|function)', container : '(string|element|boolean)', fallbackPlacement : '(string|array)', boundary : '(string|element)' @@ -285,9 +285,7 @@ class Tooltip { this._popper = new Popper(this.element, tip, { placement: attachment, modifiers: { - offset: { - offset: this.config.offset - }, + offset: this._getOffset(), flip: { behavior: this.config.fallbackPlacement }, @@ -450,6 +448,25 @@ class Tooltip { // Private + _getOffset() { + const offset = {} + + if (typeof this.config.offset === 'function') { + offset.fn = (data) => { + data.offsets = { + ...data.offsets, + ...this.config.offset(data.offsets, this.element) || {} + } + + return data + } + } else { + offset.offset = this.config.offset + } + + return offset + } + _getContainer() { if (this.config.container === false) { return document.body diff --git a/js/tests/unit/tooltip.js b/js/tests/unit/tooltip.js index 54dbe57bd86b..30829d24d56d 100644 --- a/js/tests/unit/tooltip.js +++ b/js/tests/unit/tooltip.js @@ -1069,4 +1069,41 @@ $(function () { assert.strictEqual(tooltip._isEnabled, true) }) + + QUnit.test('should create offset modifier correctly when offset option is a function', function (assert) { + assert.expect(2) + + var getOffset = function (offsets) { + return offsets + } + + var $trigger = $('') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + offset: getOffset + }) + + var tooltip = $trigger.data('bs.tooltip') + var offset = tooltip._getOffset() + + assert.ok(typeof offset.offset === 'undefined') + assert.ok(typeof offset.fn === 'function') + }) + + QUnit.test('should create offset modifier correctly when offset option is not a function', function (assert) { + assert.expect(2) + + var myOffset = 42 + var $trigger = $('') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + offset: myOffset + }) + + var tooltip = $trigger.data('bs.tooltip') + var offset = tooltip._getOffset() + + assert.strictEqual(offset.offset, myOffset) + assert.ok(typeof offset.fn === 'undefined') + }) }) diff --git a/package.json b/package.json index e0eb83b566aa..68595485c171 100644 --- a/package.json +++ b/package.json @@ -186,11 +186,11 @@ }, { "path": "./dist/js/bootstrap.bundle.min.js", - "maxSize": "21 kB" + "maxSize": "21.25 kB" }, { "path": "./dist/js/bootstrap.js", - "maxSize": "22.5 kB" + "maxSize": "23 kB" }, { "path": "./dist/js/bootstrap.min.js", diff --git a/site/docs/4.2/components/tooltips.md b/site/docs/4.2/components/tooltips.md index e49db563479a..0a6be475888d 100644 --- a/site/docs/4.2/components/tooltips.md +++ b/site/docs/4.2/components/tooltips.md @@ -234,9 +234,13 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap offset - number | string + number | string | function 0 - Offset of the tooltip relative to its target. For more information refer to Popper.js's offset docs. + +

Offset of the tooltip relative to its target.

+

When a function is used to determine the offset, it is called with an object containing the offset data as its first argument. The function must return an object with the same structure. The triggering element DOM node is passed as the second argument.

+

For more information refer to Popper.js's offset docs.

+ fallbackPlacement