diff --git a/build/generate-sri.js b/build/generate-sri.js index cde818e090f6b1c216ff33f3ca8741d541b90eb5..ac897565f0b0cf7343608b8737a8033bc1ed6286 100644 --- a/build/generate-sri.js +++ b/build/generate-sri.js @@ -42,8 +42,8 @@ const files = [ configPropertyName: 'js_bundle_hash' }, { - file: 'node_modules/@popperjs/core/dist/umd/popper.min.js', - configPropertyName: 'popper_hash' + file: 'node_modules/@floating-ui/dom/dist/floating-ui.dom.umd.js', + configPropertyName: 'floating_ui_hash' } ] diff --git a/build/rollup.config.js b/build/rollup.config.js index 2d2920fd50d41ddbf0964a15278438d7d0e379cf..3a9d4d706d79fde871ce6e6156cd36b387815517 100644 --- a/build/rollup.config.js +++ b/build/rollup.config.js @@ -10,7 +10,7 @@ const BUNDLE = process.env.BUNDLE === 'true' const ESM = process.env.ESM === 'true' let fileDestination = `bootstrap${ESM ? '.esm' : ''}` -const external = ['@popperjs/core'] +const external = ['@floating-ui/dom'] const plugins = [ babel({ // Only transpile our source code @@ -20,14 +20,14 @@ const plugins = [ }) ] const globals = { - '@popperjs/core': 'Popper' + '@floating-ui/dom': 'floatingUi' } if (BUNDLE) { fileDestination += '.bundle' // Remove last entry in external array to bundle Popper external.pop() - delete globals['@popperjs/core'] + delete globals['@floating-ui/dom'] plugins.push( replace({ 'process.env.NODE_ENV': '"production"', diff --git a/config.yml b/config.yml index bb71b8d0ca1d2563c0015860d06c9187f322c11b..62e99f77d44ac8a4924fb72911c56d9a8453ce71 100644 --- a/config.yml +++ b/config.yml @@ -80,8 +80,8 @@ params: js_hash: "sha384-ODmDIVzN+pFdexxHEHFBQH3/9/vQ9uori45z4JjnFsRydbmQbmL5t1tQ0culUzyK" js_bundle: "https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" js_bundle_hash: "sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" - popper: "https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.5/dist/umd/popper.min.js" - popper_hash: "sha384-Xe+8cL9oJa6tN/veChSP7q+mnSPaj5Bcu9mPX5F5xIGE0DVittaqT5lorf0EI7Vk" + floating_ui: "https://cdn.jsdelivr.net/npm/@floating-ui/dom@0.5.4/dist/floating-ui.dom.umd.min.js" + floating_ui_hash: "sha384-Os8n9bzoYJ/ESbGD7cW0VOTLk0hO++SO+Y4swXBE2dHrxiZkjADEr5ZGOcc9CorD" anchors: min: 2 diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 601792953e0340fe452bdebe8140481b8653a841..a969fa838a05b7715f038bffd0c24f645adc2444 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -5,21 +5,18 @@ * -------------------------------------------------------------------------- */ -import * as Popper from '@popperjs/core' +import { inline, offset, shift } from '@floating-ui/dom' import { defineJQueryPlugin, - getElement, getNextActiveElement, isDisabled, - isElement, - isRTL, isVisible, noop } from './util/index' import EventHandler from './dom/event-handler' -import Manipulator from './dom/manipulator' import SelectorEngine from './dom/selector-engine' import BaseComponent from './base-component' +import FloatingUi from './util/floating-ui' /** * Constants @@ -28,7 +25,6 @@ import BaseComponent from './base-component' const NAME = 'dropdown' const DATA_KEY = 'bs.dropdown' const EVENT_KEY = `.${DATA_KEY}` -const DATA_API_KEY = '.data-api' const ESCAPE_KEY = 'Escape' const TAB_KEY = 'Tab' @@ -40,9 +36,9 @@ const EVENT_HIDE = `hide${EVENT_KEY}` const EVENT_HIDDEN = `hidden${EVENT_KEY}` const EVENT_SHOW = `show${EVENT_KEY}` const EVENT_SHOWN = `shown${EVENT_KEY}` -const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` -const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}` -const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}` +const EVENT_CLICK_DATA_API = `click${EVENT_KEY}` +const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}` +const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}` const CLASS_NAME_SHOW = 'show' const CLASS_NAME_DROPUP = 'dropup' @@ -58,30 +54,28 @@ const SELECTOR_NAVBAR = '.navbar' const SELECTOR_NAVBAR_NAV = '.navbar-nav' const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' -const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start' -const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end' -const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start' -const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end' -const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start' -const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start' const PLACEMENT_TOPCENTER = 'top' +const PLACEMENT_TOPEND = 'top-end' +const PLACEMENT_TOP = 'top-start' const PLACEMENT_BOTTOMCENTER = 'bottom' +const PLACEMENT_BOTTOMEND = 'bottom-end' +const PLACEMENT_BOTTOM = 'bottom-start' +const PLACEMENT_RIGHT = 'right-start' +const PLACEMENT_LEFT = 'left-start' const Default = { autoClose: true, - boundary: 'clippingParents', display: 'dynamic', - offset: [0, 2], - popperConfig: null, + offset: 10, + positionConfig: null, reference: 'toggle' } const DefaultType = { autoClose: '(boolean|string)', - boundary: '(string|element)', display: 'string', - offset: '(array|string|function)', - popperConfig: '(null|object|function)', + offset: '(number|array|string|function)', + positionConfig: '(null|object|function)', reference: '(string|element|object)' } @@ -93,10 +87,9 @@ class Dropdown extends BaseComponent { constructor(element, config) { super(element, config) - this._popper = null this._parent = this._element.parentNode // dropdown wrapper this._menu = SelectorEngine.findOne(SELECTOR_MENU, this._parent) - this._inNavbar = this._detectNavbar() + this._positionHelper = new FloatingUi(this._element) } // Getters @@ -132,7 +125,7 @@ class Dropdown extends BaseComponent { return } - this._createPopper() + this.update() // If this is a touch-enabled device we add extra // empty mouseover listeners to the body's immediate children; @@ -164,19 +157,9 @@ class Dropdown extends BaseComponent { this._completeHide(relatedTarget) } - dispose() { - if (this._popper) { - this._popper.destroy() - } - - super.dispose() - } - update() { - this._inNavbar = this._detectNavbar() - if (this._popper) { - this._popper.update() - } + const reference = this._positionHelper.getReferenceElement(this._config.reference, this._parent, NAME) + this._positionHelper.calculate(reference, this._menu, this._getFloatingUiConfig()) } // Private @@ -194,47 +177,28 @@ class Dropdown extends BaseComponent { } } - if (this._popper) { - this._popper.destroy() - } - this._menu.classList.remove(CLASS_NAME_SHOW) this._element.classList.remove(CLASS_NAME_SHOW) this._element.setAttribute('aria-expanded', 'false') - Manipulator.removeDataAttribute(this._menu, 'popper') + this._positionHelper.stop() EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget) } - _getConfig(config) { - config = super._getConfig(config) - - if (typeof config.reference === 'object' && !isElement(config.reference) && - typeof config.reference.getBoundingClientRect !== 'function' - ) { - // Popper virtual elements require a getBoundingClientRect method - throw new TypeError(`${NAME.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`) + _getFloatingUiConfig() { + const defaultBsConfig = { + placement: this._getPlacement(), + middleware: [offset(this._positionHelper.parseOffset(this._config.offset)), shift()] } - return config - } - - _createPopper() { - if (typeof Popper === 'undefined') { - throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)') + // Disable Popper if we have a static display or Dropdown is in Navbar + if (this._detectNavbar() || this._config.display === 'static') { + defaultBsConfig.middleware.push(inline()) } - let referenceElement = this._element - - if (this._config.reference === 'parent') { - referenceElement = this._parent - } else if (isElement(this._config.reference)) { - referenceElement = getElement(this._config.reference) - } else if (typeof this._config.reference === 'object') { - referenceElement = this._config.reference + return { + ...defaultBsConfig, + ...(typeof this._config.positionConfig === 'function' ? this._config.positionConfig(defaultBsConfig) : this._config.positionConfig) } - - const popperConfig = this._getPopperConfig() - this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig) } _isShown() { @@ -244,20 +208,15 @@ class Dropdown extends BaseComponent { _getPlacement() { const parentDropdown = this._parent - if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) { - return PLACEMENT_RIGHT + const matches = { + [CLASS_NAME_DROPEND]: PLACEMENT_RIGHT, + [CLASS_NAME_DROPSTART]: PLACEMENT_LEFT, + [CLASS_NAME_DROPUP_CENTER]: PLACEMENT_TOPCENTER, + [CLASS_NAME_DROPDOWN_CENTER]: PLACEMENT_BOTTOMCENTER } - - if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) { - return PLACEMENT_LEFT - } - - if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) { - return PLACEMENT_TOPCENTER - } - - if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) { - return PLACEMENT_BOTTOMCENTER + const match = Object.keys(matches).find(keyClass => parentDropdown.classList.contains(keyClass)) + if (match) { + return matches[match] } // We need to trim the value because custom properties can also include spaces @@ -274,52 +233,6 @@ class Dropdown extends BaseComponent { return this._element.closest(SELECTOR_NAVBAR) !== null } - _getOffset() { - const { offset } = this._config - - if (typeof offset === 'string') { - return offset.split(',').map(value => Number.parseInt(value, 10)) - } - - if (typeof offset === 'function') { - return popperData => offset(popperData, this._element) - } - - return offset - } - - _getPopperConfig() { - const defaultBsPopperConfig = { - placement: this._getPlacement(), - modifiers: [{ - name: 'preventOverflow', - options: { - boundary: this._config.boundary - } - }, - { - name: 'offset', - options: { - offset: this._getOffset() - } - }] - } - - // Disable Popper if we have a static display or Dropdown is in Navbar - if (this._inNavbar || this._config.display === 'static') { - Manipulator.setDataAttribute(this._menu, 'popper', 'static') // todo:v6 remove - defaultBsPopperConfig.modifiers = [{ - name: 'applyStyles', - enabled: false - }] - } - - return { - ...defaultBsPopperConfig, - ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig) - } - } - _selectMenuItem({ key, target }) { const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element)) @@ -364,11 +277,7 @@ class Dropdown extends BaseComponent { const composedPath = event.composedPath() const isMenuTarget = composedPath.includes(context._menu) - if ( - composedPath.includes(context._element) || - (context._config.autoClose === 'inside' && !isMenuTarget) || - (context._config.autoClose === 'outside' && isMenuTarget) - ) { + if (composedPath.includes(context._element) || (context._config.autoClose === 'inside' && !isMenuTarget) || (context._config.autoClose === 'outside' && isMenuTarget)) { continue } diff --git a/js/src/popover.js b/js/src/popover.js index acfd1ac79103c4a6afa083223c95e33588cbcd45..c82cd0bc4d28adaee158de4a9dc63cacbfca3813 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -23,9 +23,10 @@ const Default = { offset: [0, 8], placement: 'right', template: '<div class="popover" role="tooltip">' + - '<div class="popover-arrow"></div>' + + '<div class="popover-inner">' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div>' + + '</div>' + '</div>', trigger: 'click' } diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 2c5f03a29340d066267105899e9e4cd647717e1b..dfd973767b97375e05ece4f67da695d7a7901629 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -5,13 +5,14 @@ * -------------------------------------------------------------------------- */ -import * as Popper from '@popperjs/core' -import { defineJQueryPlugin, findShadowRoot, getElement, getUID, isRTL, noop } from './util/index' +import { defineJQueryPlugin, findShadowRoot, getElement, getUID, isVisible, noop } from './util/index' import { DefaultAllowlist } from './util/sanitizer' import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' import BaseComponent from './base-component' import TemplateFactory from './util/template-factory' +import FloatingUi from './util/floating-ui' +import { flip, hide, offset, shift } from '@floating-ui/dom' /** * Constants @@ -48,9 +49,9 @@ const EVENT_MOUSELEAVE = 'mouseleave' const AttachmentMap = { AUTO: 'auto', TOP: 'top', - RIGHT: isRTL() ? 'left' : 'right', + RIGHT: 'right', BOTTOM: 'bottom', - LEFT: isRTL() ? 'right' : 'left' + LEFT: 'left' } const Default = { @@ -62,16 +63,15 @@ const Default = { delay: 0, fallbackPlacements: ['top', 'right', 'bottom', 'left'], html: false, - offset: [0, 0], + offset: 0, placement: 'top', - popperConfig: null, + positionConfig: null, sanitize: true, sanitizeFn: null, selector: false, template: '<div class="tooltip" role="tooltip">' + - '<div class="tooltip-arrow"></div>' + - '<div class="tooltip-inner"></div>' + - '</div>', + '<div class="tooltip-inner"></div>' + + '</div>', title: '', trigger: 'hover focus' } @@ -85,9 +85,9 @@ const DefaultType = { delay: '(number|object)', fallbackPlacements: 'array', html: 'boolean', - offset: '(array|string|function)', + offset: '(number|array|string|function)', placement: '(string|function)', - popperConfig: '(null|object|function)', + positionConfig: '(null|object|function)', sanitize: 'boolean', sanitizeFn: '(null|function)', selector: '(string|boolean)', @@ -102,10 +102,6 @@ const DefaultType = { class Tooltip extends BaseComponent { constructor(element, config) { - if (typeof Popper === 'undefined') { - throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)') - } - super(element, config) // Private @@ -113,7 +109,7 @@ class Tooltip extends BaseComponent { this._timeout = 0 this._isHovered = false this._activeTrigger = {} - this._popper = null + this._positionHelper = new FloatingUi(this._element) this._templateFactory = null this._newContent = null @@ -194,7 +190,7 @@ class Tooltip extends BaseComponent { } show() { - if (this._element.style.display === 'none') { + if (!isVisible(this._element)) { throw new Error('Please use show on visible elements') } @@ -216,24 +212,9 @@ class Tooltip extends BaseComponent { this.tip = null } - const tip = this._getTipElement() - - this._element.setAttribute('aria-describedby', tip.getAttribute('id')) - - const { container } = this._config - - if (!this._element.ownerDocument.documentElement.contains(this.tip)) { - container.append(tip) - EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED)) - } + this.update() - if (this._popper) { - this._popper.update() - } else { - this._popper = this._createPopper(tip) - } - - tip.classList.add(CLASS_NAME_SHOW) + this.tip.classList.add(CLASS_NAME_SHOW) // If this is a touch-enabled device we add extra // empty mouseover listeners to the body's immediate children; @@ -291,24 +272,17 @@ class Tooltip extends BaseComponent { } if (!this._isHovered) { + this._positionHelper.stop() tip.remove() } this._element.removeAttribute('aria-describedby') EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN)) - - this._disposePopper() } this._queueCallback(complete, this.tip, this._isAnimated()) } - update() { - if (this._popper) { - this._popper.update() - } - } - // Protected _isWithContent() { return Boolean(this._getTitle()) @@ -317,6 +291,14 @@ class Tooltip extends BaseComponent { _getTipElement() { if (!this.tip) { this.tip = this._createTipElement(this._newContent || this._getContentForTemplate()) + this._element.setAttribute('aria-describedby', this.tip.getAttribute('id')) + } + + const { container } = this._config + + if (!this._element.ownerDocument.documentElement.contains(this.tip)) { + container.append(this.tip) + EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED)) } return this.tip @@ -331,8 +313,6 @@ class Tooltip extends BaseComponent { } tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW) - // todo: on v6 the following can be achieved with CSS only - tip.classList.add(`bs-${this.constructor.NAME}-auto`) const tipId = getUID(this.constructor.NAME).toString() @@ -392,79 +372,39 @@ class Tooltip extends BaseComponent { return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW) } - _createPopper(tip) { - const placement = typeof this._config.placement === 'function' ? - this._config.placement.call(this, tip, this._element) : - this._config.placement - const attachment = AttachmentMap[placement.toUpperCase()] - return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment)) - } - - _getOffset() { - const { offset } = this._config - - if (typeof offset === 'string') { - return offset.split(',').map(value => Number.parseInt(value, 10)) + update() { + this._positionHelper.calculate(this._element, this._getTipElement(), this._getFloatingUiConfig(), { position: 'fixed' }) + } + + _getFloatingUiConfig() { + const defaultBsConfig = { + strategy: 'fixed', + placement: this._getPlacement(), + middleware: [ + offset(this._positionHelper.parseOffset(this._config.offset)), + flip({ fallbackPlacements: this._config.fallbackPlacements }), + shift(), + hide() + ] } - if (typeof offset === 'function') { - return popperData => offset(popperData, this._element) + return { + ...defaultBsConfig, + ...(typeof this._config.positionConfig === 'function' ? this._config.positionConfig(defaultBsConfig) : this._config.positionConfig) } + } - return offset + _getPlacement() { + const placement = typeof this._config.placement === 'function' ? + this._config.placement.call(this, this.tip, this._element) : + this._config.placement + return AttachmentMap[placement.toUpperCase()] } _resolvePossibleFunction(arg) { return typeof arg === 'function' ? arg.call(this._element) : arg } - _getPopperConfig(attachment) { - const defaultBsPopperConfig = { - placement: attachment, - modifiers: [ - { - name: 'flip', - options: { - fallbackPlacements: this._config.fallbackPlacements - } - }, - { - name: 'offset', - options: { - offset: this._getOffset() - } - }, - { - name: 'preventOverflow', - options: { - boundary: this._config.boundary - } - }, - { - name: 'arrow', - options: { - element: `.${this.constructor.NAME}-arrow` - } - }, - { - name: 'preSetPlacement', - enabled: true, - phase: 'beforeMain', - fn: data => { - // Pre-set Popper's placement attribute in order to read the arrow sizes properly. - // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement - this._getTipElement().setAttribute('data-popper-placement', data.state.placement) - } - } - ] - } - - return { - ...defaultBsPopperConfig, - ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig) - } - } - _setListeners() { const triggers = this._config.trigger.split(' ') @@ -621,13 +561,6 @@ class Tooltip extends BaseComponent { return config } - _disposePopper() { - if (this._popper) { - this._popper.destroy() - this._popper = null - } - } - // Static static jQueryInterface(config) { return this.each(function () { diff --git a/js/src/util/floating-ui.js b/js/src/util/floating-ui.js new file mode 100644 index 0000000000000000000000000000000000000000..5501daf85664b4d39c5fc03ec38c01766a12f6b8 --- /dev/null +++ b/js/src/util/floating-ui.js @@ -0,0 +1,92 @@ +// import {computePosition, flip, shift} from '@floating-ui/dom' +// +// +import { autoUpdate, computePosition } from '@floating-ui/dom' +import { getElement, isElement } from './index' +import Manipulator from '../dom/manipulator' + +class FloatingUi { + constructor(element) { + if (typeof computePosition === 'undefined') { + throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)') + } + + this._element = element + this._cleanup = null + } + + calculate(reference, floatingEl, config, extraCss = {}) { + this._cleanup = autoUpdate(reference, floatingEl, () => { + computePosition(reference, floatingEl, config) + .then(({ x, y, placement, middlewareData }) => { + const positionCss = { + left: `${x}px`, + top: `${y}px` + } + console.log(middlewareData) // eslint-disable-line no-console + if (middlewareData.hide) { + const { referenceHidden } = middlewareData.hide + + Object.assign(floatingEl.style, { + visibility: referenceHidden ? 'hidden' : 'visible' + }) + } + + Object.assign(floatingEl.style, { ...positionCss, ...extraCss }) + Manipulator.setDataAttribute(floatingEl, 'placement', placement) + }) + }) + } + + stop() { + if (this._cleanup) { + this._cleanup() + } + } + + getReferenceElement(reference, parent, PluginName) { + if (reference === 'parent') { + return parent + } + + if (isElement(reference)) { + return getElement(reference) + } + + if (typeof reference === 'object') { + if (typeof reference.getBoundingClientRect !== 'function') { + throw new TypeError(`${PluginName.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`) + } + + return reference + } + + return this._element + } + + parseOffset(value) { + console.log(value) // eslint-disable-line no-console + if (typeof value === 'function') { + return popperData => value(popperData, this._element) + } + + if (typeof value === 'string') { + console.log('offset', value) // eslint-disable-line no-console + value = [ + Number.parseInt(value.split(',')[0], 10), + Number.parseInt(value.split(',')[1] || 0, 10) + ] + } + + if (Array.isArray(value)) { + return { + mainAxis: value[0], + alignmentAxis: value[1] + } + } + + return value + } +} + +export default FloatingUi diff --git a/package-lock.json b/package-lock.json index b2511343d0f6b5d7f8c9da0efba598e7eb078f50..4fd170f4874265bc924299d0cdde712b7e57f22d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,9 @@ } ], "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^0.5.4" + }, "devDependencies": { "@babel/cli": "^7.18.10", "@babel/core": "^7.18.10", @@ -1770,6 +1773,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@floating-ui/core": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz", + "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==" + }, + "node_modules/@floating-ui/dom": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz", + "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==", + "dependencies": { + "@floating-ui/core": "^0.7.3" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", @@ -11705,6 +11721,19 @@ } } }, + "@floating-ui/core": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz", + "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==" + }, + "@floating-ui/dom": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz", + "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==", + "requires": { + "@floating-ui/core": "^0.7.3" + } + }, "@humanwhocodes/config-array": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", diff --git a/package.json b/package.json index 32ec47f86b954b422842c367b680dc79fd6b94c2..2cabf2a3cf04403fd82071665ce790ee0e6f4f16 100644 --- a/package.json +++ b/package.json @@ -101,13 +101,13 @@ "watch-js-docs": "nodemon --watch site/assets/js/ --ext js --exec \"npm run js-lint\"" }, "peerDependencies": { - "@popperjs/core": "^2.11.5" + "@floating-ui/dom": "^0.5.4" }, "devDependencies": { "@babel/cli": "^7.18.10", "@babel/core": "^7.18.10", "@babel/preset-env": "^7.18.10", - "@popperjs/core": "^2.11.5", + "@floating-ui/dom": "^0.5.4", "@rollup/plugin-babel": "^5.3.1", "@rollup/plugin-commonjs": "^22.0.1", "@rollup/plugin-node-resolve": "^13.3.0", @@ -174,7 +174,7 @@ }, "dependencies": {}, "peerDependencies": { - "@popperjs/core": "^2.11.5" + "@floating-ui/dom": "^0.5.4" } } } diff --git a/scss/_dropdown.scss b/scss/_dropdown.scss index 62125b96783a25934f469e7c5e270f1050d02c2c..de96a9e1bcb76ec7d42ed143be992afe7d9b8da1 100644 --- a/scss/_dropdown.scss +++ b/scss/_dropdown.scss @@ -61,12 +61,6 @@ @include border-radius(var(--#{$prefix}dropdown-border-radius)); @include box-shadow(var(--#{$prefix}dropdown-box-shadow)); - &[data-bs-popper] { - top: 100%; - left: 0; - margin-top: var(--#{$prefix}dropdown-spacer); - } - @if $dropdown-padding-y == 0 { > .dropdown-item:first-child, > li:first-child .dropdown-item { @@ -82,7 +76,7 @@ // scss-docs-start responsive-breakpoints // We deliberately hardcode the `bs-` prefix because we check -// this custom property in JS to determine Popper's positioning +// this custom property in JS to determine positioning @each $breakpoint in map-keys($grid-breakpoints) { @include media-breakpoint-up($breakpoint) { @@ -90,20 +84,10 @@ .dropdown-menu#{$infix}-start { --bs-position: start; - - &[data-bs-popper] { - right: auto; - left: 0; - } } .dropdown-menu#{$infix}-end { --bs-position: end; - - &[data-bs-popper] { - right: 0; - left: auto; - } } } } @@ -112,26 +96,12 @@ // Allow for dropdowns to go bottom up (aka, dropup-menu) // Just add .dropup after the standard .dropdown class and you're set. .dropup { - .dropdown-menu[data-bs-popper] { - top: auto; - bottom: 100%; - margin-top: 0; - margin-bottom: var(--#{$prefix}dropdown-spacer); - } - .dropdown-toggle { @include caret(up); } } .dropend { - .dropdown-menu[data-bs-popper] { - top: 0; - right: auto; - left: 100%; - margin-top: 0; - margin-left: var(--#{$prefix}dropdown-spacer); - } .dropdown-toggle { @include caret(end); @@ -142,14 +112,6 @@ } .dropstart { - .dropdown-menu[data-bs-popper] { - top: 0; - right: 100%; - left: auto; - margin-top: 0; - margin-right: var(--#{$prefix}dropdown-spacer); - } - .dropdown-toggle { @include caret(start); &::before { diff --git a/scss/_popover.scss b/scss/_popover.scss index b00c02959d595c1cc47e58be8f908ac393cb6e47..eb13efd12fd1d996178d38e4d5597f377fabe664 100644 --- a/scss/_popover.scss +++ b/scss/_popover.scss @@ -22,6 +22,9 @@ --#{$prefix}popover-arrow-border: var(--#{$prefix}popover-border-color); // scss-docs-end popover-css-vars + position: absolute; + top: 0; + left: 0; z-index: var(--#{$prefix}popover-zindex); display: block; max-width: var(--#{$prefix}popover-max-width); @@ -31,150 +34,122 @@ @include font-size(var(--#{$prefix}popover-font-size)); // Allow breaking very long words so they don't overflow the popover's bounds word-wrap: break-word; + + &::before, + &::after { + position: absolute; + display: block; + content: ""; + border-color: transparent; + border-style: solid; + border-width: 0; + transform: translateX(-50%); + } +} + +.popover-inner { + margin: var(--#{$prefix}popover-arrow-height); background-color: var(--#{$prefix}popover-bg); background-clip: padding-box; border: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color); @include border-radius(var(--#{$prefix}popover-border-radius)); @include box-shadow(var(--#{$prefix}popover-box-shadow)); - - .popover-arrow { - display: block; - width: var(--#{$prefix}popover-arrow-width); - height: var(--#{$prefix}popover-arrow-height); - - &::before, - &::after { - position: absolute; - display: block; - content: ""; - border-color: transparent; - border-style: solid; - border-width: 0; - } - } } -.bs-popover-top { - > .popover-arrow { - bottom: calc((var(--#{$prefix}popover-arrow-height) * -1) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list - - &::before, - &::after { - border-width: var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list - } +.popover[data-bs-placement="top"] { + &::before, + &::after { + left: 50%; + border-width: var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list + } - &::before { - bottom: 0; - border-top-color: var(--#{$prefix}popover-arrow-border); - } + &::before { + bottom: 0; + border-top-color: var(--#{$prefix}popover-arrow-border); + } - &::after { - bottom: var(--#{$prefix}popover-border-width); - border-top-color: var(--#{$prefix}popover-bg); - } + &::after { + bottom: var(--#{$prefix}popover-border-width); + border-top-color: var(--#{$prefix}popover-bg); } } -/* rtl:begin:ignore */ -.bs-popover-end { - > .popover-arrow { - left: calc((var(--#{$prefix}popover-arrow-height) * -1) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list - width: var(--#{$prefix}popover-arrow-height); - height: var(--#{$prefix}popover-arrow-width); - - &::before, - &::after { - border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list - } - - &::before { - left: 0; - border-right-color: var(--#{$prefix}popover-arrow-border); - } - - &::after { - left: var(--#{$prefix}popover-border-width); - border-right-color: var(--#{$prefix}popover-bg); - } +.popover[data-bs-placement="bottom"] { + &::before, + &::after { + left: 50%; + border-width: 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list } -} -/* rtl:end:ignore */ + &::before { + top: 0; + border-bottom-color: var(--#{$prefix}popover-arrow-border); + } -.bs-popover-bottom { - > .popover-arrow { - top: calc((var(--#{$prefix}popover-arrow-height) * -1) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list + &::after { + top: var(--#{$prefix}popover-border-width); + border-bottom-color: var(--#{$prefix}popover-bg); + } +} - &::before, - &::after { - border-width: 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list - } - &::before { - top: 0; - border-bottom-color: var(--#{$prefix}popover-arrow-border); - } +/* rtl:begin:ignore */ - &::after { - top: var(--#{$prefix}popover-border-width); - border-bottom-color: var(--#{$prefix}popover-bg); - } +.popover[data-bs-placement="right"] { + &::before, + &::after { + top: 50%; + border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list + transform: translateY(-50%); } - // This will remove the popover-header's border just below the arrow - .popover-header::before { - position: absolute; - top: 0; - left: 50%; - display: block; - width: var(--#{$prefix}popover-arrow-width); - margin-left: calc(var(--#{$prefix}popover-arrow-width) * -.5); // stylelint-disable-line function-disallowed-list - content: ""; - border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-header-bg); + &::before { + left: 0; + border-right-color: var(--#{$prefix}popover-arrow-border); } -} -/* rtl:begin:ignore */ -.bs-popover-start { - > .popover-arrow { - right: calc((var(--#{$prefix}popover-arrow-height) * -1) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list - width: var(--#{$prefix}popover-arrow-height); - height: var(--#{$prefix}popover-arrow-width); - - &::before, - &::after { - border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list - } - - &::before { - right: 0; - border-left-color: var(--#{$prefix}popover-arrow-border); - } - - &::after { - right: var(--#{$prefix}popover-border-width); - border-left-color: var(--#{$prefix}popover-bg); - } + &::after { + left: var(--#{$prefix}popover-border-width); + border-right-color: var(--#{$prefix}popover-bg); } } -/* rtl:end:ignore */ -.bs-popover-auto { - &[data-popper-placement^="top"] { - @extend .bs-popover-top; +.popover[data-bs-placement="left"] { + &::before, + &::after { + top: 50%; + border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list + transform: translateY(-50%); } - &[data-popper-placement^="right"] { - @extend .bs-popover-end; - } - &[data-popper-placement^="bottom"] { - @extend .bs-popover-bottom; + + &::before { + right: 0; + border-left-color: var(--#{$prefix}popover-arrow-border); } - &[data-popper-placement^="left"] { - @extend .bs-popover-start; + + &::after { + right: var(--#{$prefix}popover-border-width); + border-left-color: var(--#{$prefix}popover-bg); } } + +/* rtl:end:ignore */ + +// This will remove the popover-header's border just below the arrow +.popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: var(--#{$prefix}popover-arrow-width); + margin-left: calc(var(--#{$prefix}popover-arrow-width) * -.5); // stylelint-disable-line function-disallowed-list + content: ""; + border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-header-bg); +} + + // Offset the popover to account for the popover arrow .popover-header { padding: var(--#{$prefix}popover-header-padding-y) var(--#{$prefix}popover-header-padding-x); diff --git a/scss/_tooltip.scss b/scss/_tooltip.scss index 7da3df3e00c6b0768d7f9960f7f346b1bde62310..8aae09528e1e53e91d7c9813a2dd907011d7af80 100644 --- a/scss/_tooltip.scss +++ b/scss/_tooltip.scss @@ -5,7 +5,6 @@ --#{$prefix}tooltip-max-width: #{$tooltip-max-width}; --#{$prefix}tooltip-padding-x: #{$tooltip-padding-x}; --#{$prefix}tooltip-padding-y: #{$tooltip-padding-y}; - --#{$prefix}tooltip-margin: #{$tooltip-margin}; @include rfs($tooltip-font-size, --#{$prefix}tooltip-font-size); --#{$prefix}tooltip-color: #{$tooltip-color}; --#{$prefix}tooltip-bg: #{$tooltip-bg}; @@ -15,11 +14,12 @@ --#{$prefix}tooltip-arrow-height: #{$tooltip-arrow-height}; // scss-docs-end tooltip-css-vars + position: absolute; + top: 0; + left: 0; z-index: var(--#{$prefix}tooltip-zindex); display: block; padding: var(--#{$prefix}tooltip-arrow-height); - margin: var(--#{$prefix}tooltip-margin); - @include deprecate("`$tooltip-margin`", "v5", "v5.x", true); // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element. // So reset our font and text properties to avoid inheriting weird values. @include reset-text(); @@ -30,83 +30,44 @@ &.show { opacity: var(--#{$prefix}tooltip-opacity); } - .tooltip-arrow { - display: block; - width: var(--#{$prefix}tooltip-arrow-width); - height: var(--#{$prefix}tooltip-arrow-height); - - &::before { - position: absolute; - content: ""; - border-color: transparent; - border-style: solid; - } - } -} - -.bs-tooltip-top .tooltip-arrow { - bottom: 0; - &::before { - top: -1px; - border-width: var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list - border-top-color: var(--#{$prefix}tooltip-bg); + position: absolute; + content: ""; + border-color: transparent; + border-style: solid; + transform: translateX(-50%); } -} - -/* rtl:begin:ignore */ -.bs-tooltip-end .tooltip-arrow { - left: 0; - width: var(--#{$prefix}tooltip-arrow-height); - height: var(--#{$prefix}tooltip-arrow-width); - &::before { - right: -1px; - border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list - border-right-color: var(--#{$prefix}tooltip-bg); - } } -/* rtl:end:ignore */ +.tooltip[data-bs-placement="top"]::before { + bottom: 0; + left: 50%; + border-width: var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list + border-top-color: var(--#{$prefix}tooltip-bg); +} -.bs-tooltip-bottom .tooltip-arrow { +.tooltip[data-bs-placement="bottom"]::before { top: 0; - - &::before { - bottom: -1px; - border-width: 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list - border-bottom-color: var(--#{$prefix}tooltip-bg); - } + left: 50%; + border-width: 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list + border-bottom-color: var(--#{$prefix}tooltip-bg); } -/* rtl:begin:ignore */ -.bs-tooltip-start .tooltip-arrow { - right: 0; - width: var(--#{$prefix}tooltip-arrow-height); - height: var(--#{$prefix}tooltip-arrow-width); - - &::before { - left: -1px; - border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list - border-left-color: var(--#{$prefix}tooltip-bg); - } +.tooltip[data-bs-placement="right"]::before { + top: 50%; + left: 0; + border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list + border-right-color: var(--#{$prefix}tooltip-bg); + transform: translateY(-50%); } -/* rtl:end:ignore */ - -.bs-tooltip-auto { - &[data-popper-placement^="top"] { - @extend .bs-tooltip-top; - } - &[data-popper-placement^="right"] { - @extend .bs-tooltip-end; - } - &[data-popper-placement^="bottom"] { - @extend .bs-tooltip-bottom; - } - &[data-popper-placement^="left"] { - @extend .bs-tooltip-start; - } +.tooltip[data-bs-placement="left"]::before { + top: 50%; + right: 0; + border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list + border-left-color: var(--#{$prefix}tooltip-bg); + transform: translateY(-50%); } // Wrapper for the tooltip content diff --git a/scss/_variables.scss b/scss/_variables.scss index 82d33b0baf127101e2ef5012b9763dfaf5b086fa..0013865cdc50398a3bf2ee82bb145e005b5b0aaf 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -1299,7 +1299,6 @@ $tooltip-border-radius: $border-radius !default; $tooltip-opacity: .9 !default; $tooltip-padding-y: $spacer * .25 !default; $tooltip-padding-x: $spacer * .5 !default; -$tooltip-margin: null !default; // TODO: remove this in v6 $tooltip-arrow-width: .8rem !default; $tooltip-arrow-height: .4rem !default; diff --git a/site/assets/js/snippets.js b/site/assets/js/snippets.js index 53f8a786ec6fd286f3b9bdd3be9c428c992d44c0..075c5e50ce13a34e98c68b4591712cd302e71bc0 100644 --- a/site/assets/js/snippets.js +++ b/site/assets/js/snippets.js @@ -23,7 +23,7 @@ // Instantiate all tooltips in a docs or StackBlitz page document.querySelectorAll('[data-bs-toggle="tooltip"]') .forEach(tooltip => { - new bootstrap.Tooltip(tooltip) + new bootstrap.Tooltip(tooltip, { trigger: 'click' }) }) // -------- diff --git a/site/content/docs/5.2/components/dropdowns.md b/site/content/docs/5.2/components/dropdowns.md index ec7e584b5b5081600b0d2cf1331f7938ebb9a6de..7eb31bbe2fd07bf2b23daccb648ab176cd1ac9cd 100644 --- a/site/content/docs/5.2/components/dropdowns.md +++ b/site/content/docs/5.2/components/dropdowns.md @@ -10,7 +10,7 @@ toc: true Dropdowns are toggleable, contextual overlays for displaying lists of links and more. They're made interactive with the included Bootstrap dropdown JavaScript plugin. They're toggled by clicking, not by hovering; this is [an intentional design decision](https://markdotto.com/2012/02/27/bootstrap-explained-dropdowns/). -Dropdowns are built on a third party library, [Popper](https://popper.js.org/), which provides dynamic positioning and viewport detection. Be sure to include [popper.min.js]({{< param "cdn.popper" >}}) before Bootstrap's JavaScript or use `bootstrap.bundle.min.js` / `bootstrap.bundle.js` which contains Popper. Popper isn't used to position dropdowns in navbars though as dynamic positioning isn't required. +Dropdowns are built on a third party library, [Popper](https://popper.js.org/), which provides dynamic positioning and viewport detection. Be sure to include [popper.min.js]({{< param "cdn.floating_ui" >}}) before Bootstrap's JavaScript or use `bootstrap.bundle.min.js` / `bootstrap.bundle.js` which contains Popper. Popper isn't used to position dropdowns in navbars though as dynamic positioning isn't required. ## Accessibility diff --git a/site/content/docs/5.2/components/popovers.md b/site/content/docs/5.2/components/popovers.md index 87e756434be240fc991ef964639c75e78ed8adba..82953bd9eb4271006c202b2060d5481ee677a60b 100644 --- a/site/content/docs/5.2/components/popovers.md +++ b/site/content/docs/5.2/components/popovers.md @@ -10,7 +10,7 @@ toc: true Things to know when using the popover plugin: -- Popovers rely on the third party library [Popper](https://popper.js.org/) for positioning. You must include [popper.min.js]({{< param "cdn.popper" >}}) before `bootstrap.js`, or use one `bootstrap.bundle.min.js` which contains Popper. +- Popovers rely on the third party library [Popper](https://popper.js.org/) for positioning. You must include [popper.min.js]({{< param "cdn.floating_ui" >}}) before `bootstrap.js`, or use one `bootstrap.bundle.min.js` which contains Popper. - Popovers require the [popover plugin]({{< docsref "/components/popovers" >}}) as a dependency. - Popovers are opt-in for performance reasons, so **you must initialize them yourself**. - Zero-length `title` and `content` values will never show a popover. diff --git a/site/content/docs/5.2/components/tooltips.md b/site/content/docs/5.2/components/tooltips.md index 9f1bbdc8daf63c1330ee3b549ca80bf6bee12e79..2c78820d8d04351679692fcf7d88dd332a536d2b 100644 --- a/site/content/docs/5.2/components/tooltips.md +++ b/site/content/docs/5.2/components/tooltips.md @@ -10,7 +10,7 @@ toc: true Things to know when using the tooltip plugin: -- Tooltips rely on the third party library [Popper](https://popper.js.org/) for positioning. You must include [popper.min.js]({{< param "cdn.popper" >}}) before `bootstrap.js`, or use one `bootstrap.bundle.min.js` which contains Popper. +- Tooltips rely on the third party library [Popper](https://popper.js.org/) for positioning. You must include [popper.min.js]({{< param "cdn.floating_ui" >}}) before `bootstrap.js`, or use one `bootstrap.bundle.min.js` which contains Popper. - Tooltips are opt-in for performance reasons, so **you must initialize them yourself**. - Tooltips with zero-length titles are never displayed. - Specify `container: 'body'` to avoid rendering problems in more complex components (like our input groups, button groups, etc). diff --git a/site/content/docs/5.2/getting-started/download.md b/site/content/docs/5.2/getting-started/download.md index eeffdc83e5c779cc6636cd26e2d8a60e0d50eaa4..32a75f7c6059dd48781098f2420915e6d4678d37 100644 --- a/site/content/docs/5.2/getting-started/download.md +++ b/site/content/docs/5.2/getting-started/download.md @@ -46,7 +46,7 @@ Skip the download with [jsDelivr](https://www.jsdelivr.com/) to deliver cached v If you're using our compiled JavaScript and prefer to include Popper separately, add Popper before our JS, via a CDN preferably. ```html -<script src="{{< param "cdn.popper" >}}" integrity="{{< param "cdn.popper_hash" >}}" crossorigin="anonymous"></script> +<script src="{{< param "cdn.floating_ui" >}}" integrity="{{< param "cdn.floating_ui_hash" >}}" crossorigin="anonymous"></script> <script src="{{< param "cdn.js" >}}" integrity="{{< param "cdn.js_hash" >}}" crossorigin="anonymous"></script> ``` diff --git a/site/content/docs/5.2/getting-started/introduction.md b/site/content/docs/5.2/getting-started/introduction.md index 579e04b2f4109fc3f337f2d268bb0c366a6bde64..096e5330378556bc56523585392daee99dd4f2ba 100644 --- a/site/content/docs/5.2/getting-started/introduction.md +++ b/site/content/docs/5.2/getting-started/introduction.md @@ -53,7 +53,7 @@ Get started by including Bootstrap's production-ready CSS and JavaScript via CDN You can also include [Popper](https://popper.js.org/) and our JS separately. If you don't plan to use dropdowns, popovers, or tooltips, save some kilobytes by not including Popper. ```html - <script src="{{< param "cdn.popper" >}}" integrity="{{< param "cdn.popper_hash" >}}" crossorigin="anonymous"></script> + <script src="{{< param "cdn.floating_ui" >}}" integrity="{{< param "cdn.floating_ui_hash" >}}" crossorigin="anonymous"></script> <script src="{{< param "cdn.js" >}}" integrity="{{< param "cdn.js_hash" >}}" crossorigin="anonymous"></script> ``` diff --git a/site/content/docs/5.2/getting-started/javascript.md b/site/content/docs/5.2/getting-started/javascript.md index fa157e006c18b76e56e8d9c69624421d227b2cf4..48a1e3114880c2e473ac990ac306be5a4ee3a0f9 100644 --- a/site/content/docs/5.2/getting-started/javascript.md +++ b/site/content/docs/5.2/getting-started/javascript.md @@ -71,7 +71,7 @@ To fix this, you can use an `importmap` to resolve the arbitrary module names to <script type="importmap"> { "imports": { - "@popperjs/core": "{{< param "cdn.popper" >}}", + "@popperjs/core": "{{< param "cdn.floating_ui" >}}", "bootstrap": "https://cdn.jsdelivr.net/npm/bootstrap@{{< param "current_version" >}}/dist/js/bootstrap.esm.min.js" } } diff --git a/site/content/docs/5.2/getting-started/rtl.md b/site/content/docs/5.2/getting-started/rtl.md index f4abf050baee7e814cc8cca6dd1c7e9f239314e7..9511e71fb4f0cf7fb60d79ff35e29f9f3cb563a8 100644 --- a/site/content/docs/5.2/getting-started/rtl.md +++ b/site/content/docs/5.2/getting-started/rtl.md @@ -58,7 +58,7 @@ You can see the above requirements reflected in this modified RTL starter templa <!-- Option 2: Separate Popper and Bootstrap JS --> <!-- - <script src="{{< param "cdn.popper" >}}" integrity="{{< param "cdn.popper_hash" >}}" crossorigin="anonymous"></script> + <script src="{{< param "cdn.floating_ui" >}}" integrity="{{< param "cdn.floating_ui_hash" >}}" crossorigin="anonymous"></script> <script src="{{< param "cdn.js" >}}" integrity="{{< param "cdn.js_hash" >}}" crossorigin="anonymous"></script> --> </body>