diff --git a/README.md b/README.md index 97b5c770d..1e8edf958 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ Have a bug or a feature request? Please first read the [issue guidelines](https: Bootstrap's documentation, included in this repo in the root directory, is built with [Hugo](https://gohugo.io/) and publicly hosted on GitHub Pages at . The docs may also be run locally. -Documentation search is powered by [Algolia's DocSearch](https://community.algolia.com/docsearch/). Working on our search? Be sure to set `debug: true` in `site/assets/js/src/search.js` file. +Documentation search is powered by [Algolia's DocSearch](https://community.algolia.com/docsearch/). Working on our search? Be sure to set `debug: true` in `site/assets/js/search.js`. ### Running documentation locally diff --git a/js/src/alert.js b/js/src/alert.js index 724cda017..f1f612232 100644 --- a/js/src/alert.js +++ b/js/src/alert.js @@ -15,6 +15,7 @@ import { } from './util/index' import Data from './dom/data' import EventHandler from './dom/event-handler' +import BaseComponent from './base-component' /** * ------------------------------------------------------------------------ @@ -23,7 +24,6 @@ import EventHandler from './dom/event-handler' */ const NAME = 'alert' -const VERSION = '5.0.0-alpha3' const DATA_KEY = 'bs.alert' const EVENT_KEY = `.${DATA_KEY}` const DATA_API_KEY = '.data-api' @@ -44,19 +44,11 @@ const CLASSNAME_SHOW = 'show' * ------------------------------------------------------------------------ */ -class Alert { - constructor(element) { - this._element = element - - if (this._element) { - Data.setData(element, DATA_KEY, this) - } - } - +class Alert extends BaseComponent { // Getters - static get VERSION() { - return VERSION + static get DATA_KEY() { + return DATA_KEY } // Public @@ -72,11 +64,6 @@ class Alert { this._removeElement(rootElement) } - dispose() { - Data.removeData(this._element, DATA_KEY) - this._element = null - } - // Private _getRootElement(element) { @@ -134,10 +121,6 @@ class Alert { alertInstance.close(this) } } - - static getInstance(element) { - return Data.getData(element, DATA_KEY) - } } /** diff --git a/js/src/base-component.js b/js/src/base-component.js new file mode 100644 index 000000000..776a0052b --- /dev/null +++ b/js/src/base-component.js @@ -0,0 +1,44 @@ +/** + * -------------------------------------------------------------------------- + * Bootstrap (v5.0.0-alpha3): base-component.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + +import Data from './dom/data' + +/** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + +const VERSION = '5.0.0-alpha3' + +class BaseComponent { + constructor(element) { + if (!element) { + return + } + + this._element = element + Data.setData(element, this.constructor.DATA_KEY, this) + } + + dispose() { + Data.removeData(this._element, this.constructor.DATA_KEY) + this._element = null + } + + /** Static */ + + static getInstance(element) { + return Data.getData(element, this.DATA_KEY) + } + + static get VERSION() { + return VERSION + } +} + +export default BaseComponent diff --git a/js/src/button.js b/js/src/button.js index 42376943d..240995564 100644 --- a/js/src/button.js +++ b/js/src/button.js @@ -8,6 +8,7 @@ import { getjQuery, onDOMContentLoaded } from './util/index' import Data from './dom/data' import EventHandler from './dom/event-handler' +import BaseComponent from './base-component' /** * ------------------------------------------------------------------------ @@ -16,7 +17,6 @@ import EventHandler from './dom/event-handler' */ const NAME = 'button' -const VERSION = '5.0.0-alpha3' const DATA_KEY = 'bs.button' const EVENT_KEY = `.${DATA_KEY}` const DATA_API_KEY = '.data-api' @@ -33,16 +33,11 @@ const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` * ------------------------------------------------------------------------ */ -class Button { - constructor(element) { - this._element = element - Data.setData(element, DATA_KEY, this) - } - +class Button extends BaseComponent { // Getters - static get VERSION() { - return VERSION + static get DATA_KEY() { + return DATA_KEY } // Public @@ -52,11 +47,6 @@ class Button { this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE)) } - dispose() { - Data.removeData(this._element, DATA_KEY) - this._element = null - } - // Static static jQueryInterface(config) { @@ -72,10 +62,6 @@ class Button { } }) } - - static getInstance(element) { - return Data.getData(element, DATA_KEY) - } } /** diff --git a/js/src/carousel.js b/js/src/carousel.js index c663efbea..6443ef094 100644 --- a/js/src/carousel.js +++ b/js/src/carousel.js @@ -21,6 +21,7 @@ import Data from './dom/data' import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' import SelectorEngine from './dom/selector-engine' +import BaseComponent from './base-component' /** * ------------------------------------------------------------------------ @@ -29,7 +30,6 @@ import SelectorEngine from './dom/selector-engine' */ const NAME = 'carousel' -const VERSION = '5.0.0-alpha3' const DATA_KEY = 'bs.carousel' const EVENT_KEY = `.${DATA_KEY}` const DATA_API_KEY = '.data-api' @@ -104,8 +104,10 @@ const PointerType = { * Class Definition * ------------------------------------------------------------------------ */ -class Carousel { +class Carousel extends BaseComponent { constructor(element, config) { + super(element) + this._items = null this._interval = null this._activeElement = null @@ -116,25 +118,23 @@ class Carousel { this.touchDeltaX = 0 this._config = this._getConfig(config) - this._element = element this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element) this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0 this._pointerEvent = Boolean(window.PointerEvent) this._addEventListeners() - Data.setData(element, DATA_KEY, this) } // Getters - static get VERSION() { - return VERSION - } - static get Default() { return Default } + static get DATA_KEY() { + return DATA_KEY + } + // Public next() { @@ -218,12 +218,11 @@ class Carousel { } dispose() { + super.dispose() EventHandler.off(this._element, EVENT_KEY) - Data.removeData(this._element, DATA_KEY) this._items = null this._config = null - this._element = null this._interval = null this._isPaused = null this._isSliding = null @@ -590,10 +589,6 @@ class Carousel { event.preventDefault() } - - static getInstance(element) { - return Data.getData(element, DATA_KEY) - } } /** diff --git a/js/src/collapse.js b/js/src/collapse.js index 2ddcb0c04..feff6c917 100644 --- a/js/src/collapse.js +++ b/js/src/collapse.js @@ -21,6 +21,7 @@ import Data from './dom/data' import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' import SelectorEngine from './dom/selector-engine' +import BaseComponent from './base-component' /** * ------------------------------------------------------------------------ @@ -29,7 +30,6 @@ import SelectorEngine from './dom/selector-engine' */ const NAME = 'collapse' -const VERSION = '5.0.0-alpha3' const DATA_KEY = 'bs.collapse' const EVENT_KEY = `.${DATA_KEY}` const DATA_API_KEY = '.data-api' @@ -67,10 +67,11 @@ const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="collapse"]' * ------------------------------------------------------------------------ */ -class Collapse { +class Collapse extends BaseComponent { constructor(element, config) { + super(element) + this._isTransitioning = false - this._element = element this._config = this._getConfig(config) this._triggerArray = SelectorEngine.find( `${SELECTOR_DATA_TOGGLE}[href="#${element.id}"],` + @@ -100,20 +101,18 @@ class Collapse { if (this._config.toggle) { this.toggle() } - - Data.setData(element, DATA_KEY, this) } // Getters - static get VERSION() { - return VERSION - } - static get Default() { return Default } + static get DATA_KEY() { + return DATA_KEY + } + // Public toggle() { @@ -266,11 +265,9 @@ class Collapse { } dispose() { - Data.removeData(this._element, DATA_KEY) - + super.dispose() this._config = null this._parent = null - this._element = null this._triggerArray = null this._isTransitioning = null } @@ -368,10 +365,6 @@ class Collapse { Collapse.collapseInterface(this, config) }) } - - static getInstance(element) { - return Data.getData(element, DATA_KEY) - } } /** diff --git a/js/src/dropdown.js b/js/src/dropdown.js index b9f5a4cd3..5b8ae0645 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -19,6 +19,7 @@ import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' import Popper from 'popper.js' import SelectorEngine from './dom/selector-engine' +import BaseComponent from './base-component' /** * ------------------------------------------------------------------------ @@ -27,7 +28,6 @@ import SelectorEngine from './dom/selector-engine' */ const NAME = 'dropdown' -const VERSION = '5.0.0-alpha3' const DATA_KEY = 'bs.dropdown' const EVENT_KEY = `.${DATA_KEY}` const DATA_API_KEY = '.data-api' @@ -96,24 +96,20 @@ const DefaultType = { * ------------------------------------------------------------------------ */ -class Dropdown { +class Dropdown extends BaseComponent { constructor(element, config) { - this._element = element + super(element) + this._popper = null this._config = this._getConfig(config) this._menu = this._getMenuElement() this._inNavbar = this._detectNavbar() this._addEventListeners() - Data.setData(element, DATA_KEY, this) } // Getters - static get VERSION() { - return VERSION - } - static get Default() { return Default } @@ -122,6 +118,10 @@ class Dropdown { return DefaultType } + static get DATA_KEY() { + return DATA_KEY + } + // Public toggle() { @@ -229,9 +229,8 @@ class Dropdown { } dispose() { - Data.removeData(this._element, DATA_KEY) + super.dispose() EventHandler.off(this._element, EVENT_KEY) - this._element = null this._menu = null if (this._popper) { this._popper.destroy() @@ -489,10 +488,6 @@ class Dropdown { items[index].focus() } - - static getInstance(element) { - return Data.getData(element, DATA_KEY) - } } /** diff --git a/js/src/modal.js b/js/src/modal.js index 4309cbd9a..fdca48213 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -20,6 +20,7 @@ import Data from './dom/data' import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' import SelectorEngine from './dom/selector-engine' +import BaseComponent from './base-component' /** * ------------------------------------------------------------------------ @@ -28,7 +29,6 @@ import SelectorEngine from './dom/selector-engine' */ const NAME = 'modal' -const VERSION = '5.0.0-alpha3' const DATA_KEY = 'bs.modal' const EVENT_KEY = `.${DATA_KEY}` const DATA_API_KEY = '.data-api' @@ -37,15 +37,13 @@ const ESCAPE_KEY = 'Escape' const Default = { backdrop: true, keyboard: true, - focus: true, - show: true + focus: true } const DefaultType = { backdrop: '(boolean|string)', keyboard: 'boolean', - focus: 'boolean', - show: 'boolean' + focus: 'boolean' } const EVENT_HIDE = `hide${EVENT_KEY}` @@ -81,10 +79,11 @@ const SELECTOR_STICKY_CONTENT = '.sticky-top' * ------------------------------------------------------------------------ */ -class Modal { +class Modal extends BaseComponent { constructor(element, config) { + super(element) + this._config = this._getConfig(config) - this._element = element this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, element) this._backdrop = null this._isShown = false @@ -92,19 +91,18 @@ class Modal { this._ignoreBackdropClick = false this._isTransitioning = false this._scrollbarWidth = 0 - Data.setData(element, DATA_KEY, this) } // Getters - static get VERSION() { - return VERSION - } - static get Default() { return Default } + static get DATA_KEY() { + return DATA_KEY + } + // Public toggle(relatedTarget) { @@ -201,6 +199,8 @@ class Modal { [window, this._element, this._dialog] .forEach(htmlElement => EventHandler.off(htmlElement, EVENT_KEY)) + super.dispose() + /** * `document` has 2 events `EVENT_FOCUSIN` and `EVENT_CLICK_DATA_API` * Do not move `document` in `htmlElements` array @@ -208,10 +208,7 @@ class Modal { */ EventHandler.off(document, EVENT_FOCUSIN) - Data.removeData(this._element, DATA_KEY) - this._config = null - this._element = null this._dialog = null this._backdrop = null this._isShown = null @@ -558,15 +555,9 @@ class Modal { } data[config](relatedTarget) - } else if (_config.show) { - data.show(relatedTarget) } }) } - - static getInstance(element) { - return Data.getData(element, DATA_KEY) - } } /** diff --git a/js/src/popover.js b/js/src/popover.js index 46b693e69..97db9a3f7 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -17,7 +17,6 @@ import Tooltip from './tooltip' */ const NAME = 'popover' -const VERSION = '5.0.0-alpha3' const DATA_KEY = 'bs.popover' const EVENT_KEY = `.${DATA_KEY}` const CLASS_PREFIX = 'bs-popover' @@ -67,10 +66,6 @@ const SELECTOR_CONTENT = '.popover-body' class Popover extends Tooltip { // Getters - static get VERSION() { - return VERSION - } - static get Default() { return Default } @@ -108,7 +103,7 @@ class Popover extends Tooltip { this.setElementContent(SelectorEngine.findOne(SELECTOR_TITLE, tip), this.getTitle()) let content = this._getContent() if (typeof content === 'function') { - content = content.call(this.element) + content = content.call(this._element) } this.setElementContent(SelectorEngine.findOne(SELECTOR_CONTENT, tip), content) @@ -123,7 +118,7 @@ class Popover extends Tooltip { } _getContent() { - return this.element.getAttribute('data-bs-content') || + return this._element.getAttribute('data-bs-content') || this.config.content } @@ -161,10 +156,6 @@ class Popover extends Tooltip { } }) } - - static getInstance(element) { - return Data.getData(element, DATA_KEY) - } } /** diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js index de456e080..e3e5e76b9 100644 --- a/js/src/scrollspy.js +++ b/js/src/scrollspy.js @@ -17,6 +17,7 @@ import Data from './dom/data' import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' import SelectorEngine from './dom/selector-engine' +import BaseComponent from './base-component' /** * ------------------------------------------------------------------------ @@ -25,7 +26,6 @@ import SelectorEngine from './dom/selector-engine' */ const NAME = 'scrollspy' -const VERSION = '5.0.0-alpha3' const DATA_KEY = 'bs.scrollspy' const EVENT_KEY = `.${DATA_KEY}` const DATA_API_KEY = '.data-api' @@ -66,9 +66,9 @@ const METHOD_POSITION = 'position' * ------------------------------------------------------------------------ */ -class ScrollSpy { +class ScrollSpy extends BaseComponent { constructor(element, config) { - this._element = element + super(element) this._scrollElement = element.tagName === 'BODY' ? window : element this._config = this._getConfig(config) this._selector = `${this._config.target} ${SELECTOR_NAV_LINKS}, ${this._config.target} ${SELECTOR_LIST_ITEMS}, ${this._config.target} .${CLASS_NAME_DROPDOWN_ITEM}` @@ -81,20 +81,18 @@ class ScrollSpy { this.refresh() this._process() - - Data.setData(element, DATA_KEY, this) } // Getters - static get VERSION() { - return VERSION - } - static get Default() { return Default } + static get DATA_KEY() { + return DATA_KEY + } + // Public refresh() { @@ -141,10 +139,9 @@ class ScrollSpy { } dispose() { - Data.removeData(this._element, DATA_KEY) + super.dispose() EventHandler.off(this._scrollElement, EVENT_KEY) - this._element = null this._scrollElement = null this._config = null this._selector = null @@ -301,10 +298,6 @@ class ScrollSpy { } }) } - - static getInstance(element) { - return Data.getData(element, DATA_KEY) - } } /** diff --git a/js/src/tab.js b/js/src/tab.js index 56269e2fa..0e9755ea0 100644 --- a/js/src/tab.js +++ b/js/src/tab.js @@ -17,6 +17,7 @@ import { import Data from './dom/data' import EventHandler from './dom/event-handler' import SelectorEngine from './dom/selector-engine' +import BaseComponent from './base-component' /** * ------------------------------------------------------------------------ @@ -25,7 +26,6 @@ import SelectorEngine from './dom/selector-engine' */ const NAME = 'tab' -const VERSION = '5.0.0-alpha3' const DATA_KEY = 'bs.tab' const EVENT_KEY = `.${DATA_KEY}` const DATA_API_KEY = '.data-api' @@ -56,17 +56,11 @@ const SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active' * ------------------------------------------------------------------------ */ -class Tab { - constructor(element) { - this._element = element - - Data.setData(this._element, DATA_KEY, this) - } - +class Tab extends BaseComponent { // Getters - static get VERSION() { - return VERSION + static get DATA_KEY() { + return DATA_KEY } // Public @@ -127,11 +121,6 @@ class Tab { } } - dispose() { - Data.removeData(this._element, DATA_KEY) - this._element = null - } - // Private _activate(element, container, callback) { @@ -217,10 +206,6 @@ class Tab { } }) } - - static getInstance(element) { - return Data.getData(element, DATA_KEY) - } } /** diff --git a/js/src/toast.js b/js/src/toast.js index 1e50b0669..30df4606a 100644 --- a/js/src/toast.js +++ b/js/src/toast.js @@ -17,6 +17,7 @@ import { import Data from './dom/data' import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' +import BaseComponent from './base-component' /** * ------------------------------------------------------------------------ @@ -25,7 +26,6 @@ import Manipulator from './dom/manipulator' */ const NAME = 'toast' -const VERSION = '5.0.0-alpha3' const DATA_KEY = 'bs.toast' const EVENT_KEY = `.${DATA_KEY}` @@ -60,21 +60,17 @@ const SELECTOR_DATA_DISMISS = '[data-bs-dismiss="toast"]' * ------------------------------------------------------------------------ */ -class Toast { +class Toast extends BaseComponent { constructor(element, config) { - this._element = element + super(element) + this._config = this._getConfig(config) this._timeout = null this._setListeners() - Data.setData(element, DATA_KEY, this) } // Getters - static get VERSION() { - return VERSION - } - static get DefaultType() { return DefaultType } @@ -83,6 +79,10 @@ class Toast { return Default } + static get DATA_KEY() { + return DATA_KEY + } + // Public show() { @@ -159,9 +159,8 @@ class Toast { } EventHandler.off(this._element, EVENT_CLICK_DISMISS) - Data.removeData(this._element, DATA_KEY) - this._element = null + super.dispose() this._config = null } @@ -208,10 +207,6 @@ class Toast { } }) } - - static getInstance(element) { - return Data.getData(element, DATA_KEY) - } } /** diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 368e04b30..62b338839 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -26,6 +26,7 @@ import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' import Popper from 'popper.js' import SelectorEngine from './dom/selector-engine' +import BaseComponent from './base-component' /** * ------------------------------------------------------------------------ @@ -34,7 +35,6 @@ import SelectorEngine from './dom/selector-engine' */ const NAME = 'tooltip' -const VERSION = '5.0.0-alpha3' const DATA_KEY = 'bs.tooltip' const EVENT_KEY = `.${DATA_KEY}` const CLASS_PREFIX = 'bs-tooltip' @@ -124,12 +124,14 @@ const TRIGGER_MANUAL = 'manual' * ------------------------------------------------------------------------ */ -class Tooltip { +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) + // private this._isEnabled = true this._timeout = 0 @@ -138,20 +140,14 @@ class Tooltip { this._popper = null // Protected - this.element = element this.config = this._getConfig(config) this.tip = null this._setListeners() - Data.setData(element, this.constructor.DATA_KEY, this) } // Getters - static get VERSION() { - return VERSION - } - static get Default() { return Default } @@ -227,10 +223,8 @@ class Tooltip { dispose() { clearTimeout(this._timeout) - Data.removeData(this.element, this.constructor.DATA_KEY) - - EventHandler.off(this.element, this.constructor.EVENT_KEY) - EventHandler.off(this.element.closest(`.${CLASS_NAME_MODAL}`), 'hide.bs.modal', this._hideModalHandler) + EventHandler.off(this._element, this.constructor.EVENT_KEY) + EventHandler.off(this._element.closest(`.${CLASS_NAME_MODAL}`), 'hide.bs.modal', this._hideModalHandler) if (this.tip) { this.tip.parentNode.removeChild(this.tip) @@ -245,22 +239,22 @@ class Tooltip { } this._popper = null - this.element = null this.config = null this.tip = null + super.dispose() } show() { - if (this.element.style.display === 'none') { + if (this._element.style.display === 'none') { throw new Error('Please use show on visible elements') } if (this.isWithContent() && this._isEnabled) { - const showEvent = EventHandler.trigger(this.element, this.constructor.Event.SHOW) - const shadowRoot = findShadowRoot(this.element) + const showEvent = EventHandler.trigger(this._element, this.constructor.Event.SHOW) + const shadowRoot = findShadowRoot(this._element) const isInTheDom = shadowRoot === null ? - this.element.ownerDocument.documentElement.contains(this.element) : - shadowRoot.contains(this.element) + this._element.ownerDocument.documentElement.contains(this._element) : + shadowRoot.contains(this._element) if (showEvent.defaultPrevented || !isInTheDom) { return @@ -270,7 +264,7 @@ class Tooltip { const tipId = getUID(this.constructor.NAME) tip.setAttribute('id', tipId) - this.element.setAttribute('aria-describedby', tipId) + this._element.setAttribute('aria-describedby', tipId) this.setContent() @@ -279,7 +273,7 @@ class Tooltip { } const placement = typeof this.config.placement === 'function' ? - this.config.placement.call(this, tip, this.element) : + this.config.placement.call(this, tip, this._element) : this.config.placement const attachment = this._getAttachment(placement) @@ -288,13 +282,13 @@ class Tooltip { const container = this._getContainer() Data.setData(tip, this.constructor.DATA_KEY, this) - if (!this.element.ownerDocument.documentElement.contains(this.tip)) { + if (!this._element.ownerDocument.documentElement.contains(this.tip)) { container.appendChild(tip) } - EventHandler.trigger(this.element, this.constructor.Event.INSERTED) + EventHandler.trigger(this._element, this.constructor.Event.INSERTED) - this._popper = new Popper(this.element, tip, this._getPopperConfig(attachment)) + this._popper = new Popper(this._element, tip, this._getPopperConfig(attachment)) tip.classList.add(CLASS_NAME_SHOW) @@ -321,7 +315,7 @@ class Tooltip { const prevHoverState = this._hoverState this._hoverState = null - EventHandler.trigger(this.element, this.constructor.Event.SHOWN) + EventHandler.trigger(this._element, this.constructor.Event.SHOWN) if (prevHoverState === HOVER_STATE_OUT) { this._leave(null, this) @@ -350,12 +344,12 @@ class Tooltip { } this._cleanTipClass() - this.element.removeAttribute('aria-describedby') - EventHandler.trigger(this.element, this.constructor.Event.HIDDEN) + this._element.removeAttribute('aria-describedby') + EventHandler.trigger(this._element, this.constructor.Event.HIDDEN) this._popper.destroy() } - const hideEvent = EventHandler.trigger(this.element, this.constructor.Event.HIDE) + const hideEvent = EventHandler.trigger(this._element, this.constructor.Event.HIDE) if (hideEvent.defaultPrevented) { return } @@ -450,11 +444,11 @@ class Tooltip { } getTitle() { - let title = this.element.getAttribute('data-bs-original-title') + let title = this._element.getAttribute('data-bs-original-title') if (!title) { title = typeof this.config.title === 'function' ? - this.config.title.call(this.element) : + this.config.title.call(this._element) : this.config.title } @@ -503,7 +497,7 @@ class Tooltip { offset.fn = data => { data.offsets = { ...data.offsets, - ...(this.config.offset(data.offsets, this.element) || {}) + ...(this.config.offset(data.offsets, this._element) || {}) } return data @@ -536,7 +530,7 @@ class Tooltip { triggers.forEach(trigger => { if (trigger === 'click') { - EventHandler.on(this.element, + EventHandler.on(this._element, this.constructor.Event.CLICK, this.config.selector, event => this.toggle(event) @@ -549,12 +543,12 @@ class Tooltip { this.constructor.Event.MOUSELEAVE : this.constructor.Event.FOCUSOUT - EventHandler.on(this.element, + EventHandler.on(this._element, eventIn, this.config.selector, event => this._enter(event) ) - EventHandler.on(this.element, + EventHandler.on(this._element, eventOut, this.config.selector, event => this._leave(event) @@ -563,12 +557,12 @@ class Tooltip { }) this._hideModalHandler = () => { - if (this.element) { + if (this._element) { this.hide() } } - EventHandler.on(this.element.closest(`.${CLASS_NAME_MODAL}`), + EventHandler.on(this._element.closest(`.${CLASS_NAME_MODAL}`), 'hide.bs.modal', this._hideModalHandler ) @@ -585,12 +579,16 @@ class Tooltip { } _fixTitle() { - const title = this.element.getAttribute('title') - const originalTitleType = typeof this.element.getAttribute('data-bs-original-title') + const title = this._element.getAttribute('title') + const originalTitleType = typeof this._element.getAttribute('data-bs-original-title') if (title || originalTitleType !== 'string') { - this.element.setAttribute('data-bs-original-title', title || '') - this.element.setAttribute('title', '') + this._element.setAttribute('data-bs-original-title', title || '') + if (title && !this._element.getAttribute('aria-label') && !this._element.textContent) { + this._element.setAttribute('aria-label', title) + } + + this._element.setAttribute('title', '') } } @@ -683,7 +681,7 @@ class Tooltip { } _getConfig(config) { - const dataAttributes = Manipulator.getDataAttributes(this.element) + const dataAttributes = Manipulator.getDataAttributes(this._element) Object.keys(dataAttributes).forEach(dataAttr => { if (DISALLOWED_ATTRIBUTES.has(dataAttr)) { @@ -792,10 +790,6 @@ class Tooltip { } }) } - - static getInstance(element) { - return Data.getData(element, DATA_KEY) - } } /** diff --git a/js/tests/unit/alert.spec.js b/js/tests/unit/alert.spec.js index a746d8501..a1322f1c7 100644 --- a/js/tests/unit/alert.spec.js +++ b/js/tests/unit/alert.spec.js @@ -170,4 +170,24 @@ describe('Alert', () => { expect(fixtureEl.querySelector('.alert')).not.toBeNull() }) }) + + describe('getInstance', () => { + it('should return alert instance', () => { + fixtureEl.innerHTML = '
' + + const div = fixtureEl.querySelector('div') + const alert = new Alert(div) + + expect(Alert.getInstance(div)).toEqual(alert) + expect(Alert.getInstance(div)).toBeInstanceOf(Alert) + }) + + it('should return null when there is no alert instance', () => { + fixtureEl.innerHTML = '
' + + const div = fixtureEl.querySelector('div') + + expect(Alert.getInstance(div)).toEqual(null) + }) + }) }) diff --git a/js/tests/unit/button.spec.js b/js/tests/unit/button.spec.js index 44d7b54b1..51aa73774 100644 --- a/js/tests/unit/button.spec.js +++ b/js/tests/unit/button.spec.js @@ -128,4 +128,24 @@ describe('Button', () => { expect(btnEl.classList.contains('active')).toEqual(false) }) }) + + describe('getInstance', () => { + it('should return button instance', () => { + fixtureEl.innerHTML = '
' + + const div = fixtureEl.querySelector('div') + const button = new Button(div) + + expect(Button.getInstance(div)).toEqual(button) + expect(Button.getInstance(div)).toBeInstanceOf(Button) + }) + + it('should return null when there is no button instance', () => { + fixtureEl.innerHTML = '
' + + const div = fixtureEl.querySelector('div') + + expect(Button.getInstance(div)).toEqual(null) + }) + }) }) diff --git a/js/tests/unit/carousel.spec.js b/js/tests/unit/carousel.spec.js index 8c928c429..07b8fc311 100644 --- a/js/tests/unit/carousel.spec.js +++ b/js/tests/unit/carousel.spec.js @@ -1062,6 +1062,26 @@ describe('Carousel', () => { }) }) + describe('getInstance', () => { + it('should return carousel instance', () => { + fixtureEl.innerHTML = '
' + + const div = fixtureEl.querySelector('div') + const carousel = new Carousel(div) + + expect(Carousel.getInstance(div)).toEqual(carousel) + expect(Carousel.getInstance(div)).toBeInstanceOf(Carousel) + }) + + it('should return null when there is no carousel instance', () => { + fixtureEl.innerHTML = '
' + + const div = fixtureEl.querySelector('div') + + expect(Carousel.getInstance(div)).toEqual(null) + }) + }) + describe('jQueryInterface', () => { it('should create a carousel', () => { fixtureEl.innerHTML = '
' diff --git a/js/tests/unit/collapse.spec.js b/js/tests/unit/collapse.spec.js index c1ead859a..d53ab5964 100644 --- a/js/tests/unit/collapse.spec.js +++ b/js/tests/unit/collapse.spec.js @@ -812,6 +812,7 @@ describe('Collapse', () => { const collapse = new Collapse(div) expect(Collapse.getInstance(div)).toEqual(collapse) + expect(Collapse.getInstance(div)).toBeInstanceOf(Collapse) }) it('should return null when there is no collapse instance', () => { diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index f5f41636c..145763d20 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -1612,6 +1612,7 @@ describe('Dropdown', () => { const dropdown = new Dropdown(div) expect(Dropdown.getInstance(div)).toEqual(dropdown) + expect(Dropdown.getInstance(div)).toBeInstanceOf(Dropdown) }) it('should return null when there is no dropdown instance', () => { diff --git a/js/tests/unit/modal.spec.js b/js/tests/unit/modal.spec.js index 084f78ad1..f645e9892 100644 --- a/js/tests/unit/modal.spec.js +++ b/js/tests/unit/modal.spec.js @@ -1108,6 +1108,7 @@ describe('Modal', () => { const modal = new Modal(div) expect(Modal.getInstance(div)).toEqual(modal) + expect(Modal.getInstance(div)).toBeInstanceOf(Modal) }) it('should return null when there is no modal instance', () => { diff --git a/js/tests/unit/popover.spec.js b/js/tests/unit/popover.spec.js index e87ed1214..3c04e7ac1 100644 --- a/js/tests/unit/popover.spec.js +++ b/js/tests/unit/popover.spec.js @@ -253,6 +253,7 @@ describe('Popover', () => { const popover = new Popover(popoverEl) expect(Popover.getInstance(popoverEl)).toEqual(popover) + expect(Popover.getInstance(popoverEl)).toBeInstanceOf(Popover) }) it('should return null when there is no popover instance', () => { diff --git a/js/tests/unit/scrollspy.spec.js b/js/tests/unit/scrollspy.spec.js index 33298300c..45de56fbe 100644 --- a/js/tests/unit/scrollspy.spec.js +++ b/js/tests/unit/scrollspy.spec.js @@ -634,6 +634,16 @@ describe('ScrollSpy', () => { }) describe('getInstance', () => { + it('should return scrollspy instance', () => { + fixtureEl.innerHTML = '
' + + const div = fixtureEl.querySelector('div') + const scrollSpy = new ScrollSpy(div) + + expect(ScrollSpy.getInstance(div)).toEqual(scrollSpy) + expect(ScrollSpy.getInstance(div)).toBeInstanceOf(ScrollSpy) + }) + it('should return null if there is no instance', () => { expect(ScrollSpy.getInstance(fixtureEl)).toEqual(null) }) diff --git a/js/tests/unit/tab.spec.js b/js/tests/unit/tab.spec.js index 324c4a09b..67a85b2e4 100644 --- a/js/tests/unit/tab.spec.js +++ b/js/tests/unit/tab.spec.js @@ -417,6 +417,7 @@ describe('Tab', () => { const tab = new Tab(divEl) expect(Tab.getInstance(divEl)).toEqual(tab) + expect(Tab.getInstance(divEl)).toBeInstanceOf(Tab) }) }) diff --git a/js/tests/unit/toast.spec.js b/js/tests/unit/toast.spec.js index c4cb69a7f..a4ab4f76c 100644 --- a/js/tests/unit/toast.spec.js +++ b/js/tests/unit/toast.spec.js @@ -384,6 +384,7 @@ describe('Toast', () => { const toast = new Toast(div) expect(Toast.getInstance(div)).toEqual(toast) + expect(Toast.getInstance(div)).toBeInstanceOf(Toast) }) it('should return null when there is no toast instance', () => { diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index da2abba31..b11980751 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -1030,6 +1030,79 @@ describe('Tooltip', () => { }) }) + describe('getInstance', () => { + it('should return tooltip instance', () => { + fixtureEl.innerHTML = '
' + + const div = fixtureEl.querySelector('div') + const alert = new Tooltip(div) + + expect(Tooltip.getInstance(div)).toEqual(alert) + expect(Tooltip.getInstance(div)).toBeInstanceOf(Tooltip) + }) + + it('should return null when there is no tooltip instance', () => { + fixtureEl.innerHTML = '
' + + const div = fixtureEl.querySelector('div') + + expect(Tooltip.getInstance(div)).toEqual(null) + }) + }) + + describe('aria-label', () => { + it('should add the aria-label attribute for referencing original title', done => { + fixtureEl.innerHTML = '' + + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) + + tooltipEl.addEventListener('shown.bs.tooltip', () => { + const tooltipShown = document.querySelector('.tooltip') + + expect(tooltipShown).toBeDefined() + expect(tooltipEl.getAttribute('aria-label')).toEqual('Another tooltip') + done() + }) + + tooltip.show() + }) + + it('should not add the aria-label attribute if the attribute already exists', done => { + fixtureEl.innerHTML = '' + + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) + + tooltipEl.addEventListener('shown.bs.tooltip', () => { + const tooltipShown = document.querySelector('.tooltip') + + expect(tooltipShown).toBeDefined() + expect(tooltipEl.getAttribute('aria-label')).toEqual('Different label') + done() + }) + + tooltip.show() + }) + + it('should not add the aria-label attribute if the element has text content', done => { + fixtureEl.innerHTML = 'text content' + + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) + + tooltipEl.addEventListener('shown.bs.tooltip', () => { + const tooltipShown = document.querySelector('.tooltip') + + expect(tooltipShown).toBeDefined() + expect(tooltipEl.getAttribute('aria-label')).toBeNull() + done() + }) + + tooltip.show() + }) + }) + describe('jQueryInterface', () => { it('should create a tooltip', () => { fixtureEl.innerHTML = '
' diff --git a/package-lock.json b/package-lock.json index caa899ea1..6ad038d6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,9 +38,9 @@ "dev": true }, "@babel/core": { - "version": "7.12.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.8.tgz", - "integrity": "sha512-ra28JXL+5z73r1IC/t+FT1ApXU5LsulFDnTDntNfLQaScJUJmcHL5Qxm/IWanCToQk3bPWQo5bflbplU5r15pg==", + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", @@ -49,7 +49,7 @@ "@babel/helpers": "^7.12.5", "@babel/parser": "^7.12.7", "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.8", + "@babel/traverse": "^7.12.9", "@babel/types": "^7.12.7", "convert-source-map": "^1.7.0", "debug": "^4.1.0", @@ -1006,9 +1006,9 @@ } }, "@babel/traverse": { - "version": "7.12.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.8.tgz", - "integrity": "sha512-EIRQXPTwFEGRZyu6gXbjfpNORN1oZvwuzJbxcXjAgWV0iqXYDszN1Hx3FVm6YgZfu1ZQbCVAk3l+nIw95Xll9Q==", + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz", + "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", @@ -1141,9 +1141,9 @@ } }, "@rollup/plugin-babel": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.1.tgz", - "integrity": "sha512-Jd7oqFR2dzZJ3NWANDyBjwTtX/lYbZpVcmkHrfQcpvawHs9E4c0nYk5U2mfZ6I/DZcIvy506KZJi54XK/jxH7A==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.2.tgz", + "integrity": "sha512-MjmH7GvFT4TW8xFdIeFS3wqIX646y5tACdxkTO+khbHvS3ZcVJL6vkAHLw2wqPmkhwCfWHoNsp15VYNwW6JEJA==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.10.4", @@ -1151,9 +1151,9 @@ } }, "@rollup/plugin-commonjs": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz", - "integrity": "sha512-LuNyypCP3msCGVQJ7ki8PqYdpjfEkE/xtFa5DqlF+7IBD0JsfMZ87C58heSwIMint58sAUZbt3ITqOmdQv/dXw==", + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-17.0.0.tgz", + "integrity": "sha512-/omBIJG1nHQc+bgkYDuLpb/V08QyutP9amOrJRUSlYJZP+b/68gM//D8sxJe3Yry2QnYIr3QjR3x4AlxJEN3GA==", "dev": true, "requires": { "@rollup/pluginutils": "^3.1.0", @@ -1174,9 +1174,9 @@ } }, "@rollup/plugin-node-resolve": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-10.0.0.tgz", - "integrity": "sha512-sNijGta8fqzwA1VwUEtTvWCx2E7qC70NMsDh4ZG13byAXYigBNZMxALhKUSycBks5gupJdq0lFrKumFrRZ8H3A==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.0.0.tgz", + "integrity": "sha512-8Hrmwjn1pLYjUxcv7U7IPP0qfnzEJWHyHE6CaZ8jbLM+8axaarJRB1jB6JgKTDp5gNga+TpsgX6F8iuvgOerKQ==", "dev": true, "requires": { "@rollup/pluginutils": "^3.1.0", @@ -1184,7 +1184,7 @@ "builtin-modules": "^3.1.0", "deepmerge": "^4.2.2", "is-module": "^1.0.0", - "resolve": "^1.17.0" + "resolve": "^1.19.0" } }, "@rollup/pluginutils": { @@ -1260,9 +1260,9 @@ "dev": true }, "@types/node": { - "version": "14.14.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.9.tgz", - "integrity": "sha512-JsoLXFppG62tWTklIoO4knA+oDTYsmqWxHRvd4lpmfQRNhX6osheUOWETP2jMoV/2bEHuMra8Pp3Dmo/stBFcw==", + "version": "14.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz", + "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ==", "dev": true }, "@types/normalize-package-data": { @@ -1468,14 +1468,22 @@ "dev": true, "optional": true }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, "array-includes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", - "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz", + "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==", "dev": true, "requires": { + "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", + "es-abstract": "^1.18.0-next.1", + "get-intrinsic": "^1.0.1", "is-string": "^1.0.5" } }, @@ -1501,28 +1509,6 @@ "call-bind": "^1.0.0", "define-properties": "^1.1.3", "es-abstract": "^1.18.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } } }, "arraybuffer.slice": { @@ -1577,13 +1563,13 @@ "optional": true }, "autoprefixer": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.0.2.tgz", - "integrity": "sha512-okBmu9OMdt6DNEcZmnl0IYVv8Xl/xYWRSnc2OJ9UJEOt1u30opG1B8aLsViqKryBaYv1SKB4f85fOGZs5zYxHQ==", + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.0.4.tgz", + "integrity": "sha512-hmjYejN/WTyPP9cdNmiwtwqM8/ACVJPD5ExtwoOceQohNbgnFNiwpL2+U4bXS8aXozBL00WvH6WhqbuHf0Fgfg==", "dev": true, "requires": { "browserslist": "^4.14.7", - "caniuse-lite": "^1.0.30001157", + "caniuse-lite": "^1.0.30001161", "colorette": "^1.2.1", "normalize-range": "^0.1.2", "num2fraction": "^1.2.2", @@ -2479,9 +2465,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001159", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001159.tgz", - "integrity": "sha512-w9Ph56jOsS8RL20K9cLND3u/+5WASWdhC/PPrf+V3/HsM3uHOavWOR1Xzakbv4Puo/srmPHudkmCRWM7Aq+/UA==", + "version": "1.0.30001164", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001164.tgz", + "integrity": "sha512-G+A/tkf4bu0dSp9+duNiXc7bGds35DioCyC6vgK2m/rjA4Krpy5WeZgZyfH2f0wj2kI6yAWWucyap6oOwmY1mg==", "dev": true }, "caw": { @@ -2974,6 +2960,12 @@ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", "dev": true }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", @@ -2982,18 +2974,18 @@ "optional": true }, "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", "dev": true }, "core-js-compat": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.7.0.tgz", - "integrity": "sha512-V8yBI3+ZLDVomoWICO6kq/CD28Y4r1M7CWeO4AGpMdMfseu8bkSubBmUPySMGKRTS+su4XQ07zUkAsiu9FCWTg==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.0.tgz", + "integrity": "sha512-o9QKelQSxQMYWHXc/Gc4L8bx/4F7TTraE5rhuN8I7mKBt5dBIUpXpIR3omv70ebr8ST5R3PqbDQr+ZI3+Tt1FQ==", "dev": true, "requires": { - "browserslist": "^4.14.6", + "browserslist": "^4.14.7", "semver": "7.0.0" }, "dependencies": { @@ -3551,9 +3543,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.605", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.605.tgz", - "integrity": "sha512-PDZlEh6qelLaFLXYuIvB0aeqNoq7JS7i7aSHFds/ZnHosxyrTZftD8o84K9OwZWR+tnQFwoL76Yd5ROAhIWojQ==", + "version": "1.3.612", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.612.tgz", + "integrity": "sha512-CdrdX1B6mQqxfw+51MPWB5qA6TKWjza9f5voBtUlRfEZEwZiFaxJLrhFI8zHE9SBAuGt4h84rQU6Ho9Bauo1LA==", "dev": true }, "emoji-regex": { @@ -3703,9 +3695,9 @@ } }, "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", @@ -3713,6 +3705,7 @@ "has": "^1.0.3", "has-symbols": "^1.0.1", "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", "is-regex": "^1.1.1", "object-inspect": "^1.8.0", "object-keys": "^1.1.1", @@ -4350,6 +4343,52 @@ } } }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + } + } + }, "ext-list": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", @@ -4801,6 +4840,12 @@ "dev": true, "optional": true }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -5408,9 +5453,9 @@ } }, "hugo-bin": { - "version": "0.66.2", - "resolved": "https://registry.npmjs.org/hugo-bin/-/hugo-bin-0.66.2.tgz", - "integrity": "sha512-T/U35qAnzKubHzMi10uolB50e+RgHigHyAEnhGy6upCEp2H1sbDtsmqyzIhc+gMK8VIzJoU3vg/nqfpkFKOwsA==", + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/hugo-bin/-/hugo-bin-0.67.0.tgz", + "integrity": "sha512-EvNzhWGqE2Pb1idPPLlyIIK2VC3so3sdYShC2ohxsHCGNVWoe/D25KPJ5oIVpakxTu4SSH7Kr37RUMsa0yGQ+g==", "dev": true, "requires": { "bin-wrapper": "^4.1.0", @@ -5582,6 +5627,12 @@ "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", "dev": true }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", @@ -5659,9 +5710,9 @@ } }, "is-core-module": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", - "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", "dev": true, "requires": { "has": "^1.0.3" @@ -6423,19 +6474,19 @@ "dev": true }, "linkinator": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/linkinator/-/linkinator-2.2.2.tgz", - "integrity": "sha512-mcMMbo8n8p6qDuCQ5zZaBbxKK9jq79oWsoduBIGc0rRzukDmfLr7t6Ok1jJA7aHHFX251NmtbX2LdQvD54UHow==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/linkinator/-/linkinator-2.4.0.tgz", + "integrity": "sha512-YSecbj3/LF2xAnC4jDHEunu5Xa88lWgMemcOX4VFjtnKmYyQqhFOP5rNzqVodFUBiEgDKfNWCB9AxqfL3qMbbQ==", "dev": true, "requires": { "chalk": "^4.0.0", "cheerio": "^1.0.0-rc.2", - "finalhandler": "^1.1.2", + "express": "^4.17.1", "gaxios": "^4.0.0", "jsonexport": "^3.0.0", + "marked": "^1.2.5", "meow": "^8.0.0", "p-queue": "^6.2.1", - "serve-static": "^1.14.1", "server-destroy": "^1.0.1", "update-notifier": "^5.0.0" }, @@ -6803,6 +6854,12 @@ "object-visit": "^1.0.0" } }, + "marked": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.5.tgz", + "integrity": "sha512-2AlqgYnVPOc9WDyWu7S5DJaEZsfk6dNh/neatQ3IHUW4QLutM/VPSH9lG7bif+XjFWc9K9XR3QvR+fXuECmfdA==", + "dev": true + }, "mathml-tag-names": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", @@ -6936,12 +6993,24 @@ } } }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, "micromark": { "version": "2.10.1", "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.10.1.tgz", @@ -7115,9 +7184,9 @@ "dev": true }, "nanoid": { - "version": "3.1.18", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.18.tgz", - "integrity": "sha512-rndlDjbbHbcV3xi+R2fpJ+PbGMdfBxz5v1fATIQFq0DP64FsicQdwnKLy47K4kZHdRpmQXtz24eGsxQqamzYTA==", + "version": "3.1.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.19.tgz", + "integrity": "sha512-giCapaolEGFzITf00P2rSIjWoY3aWS3bb7AzjnfFJH4EOaAPLtyUrr3C5nQ//x4v1wTcU1JgtBpOKPOqqHrakg==", "dev": true }, "nanomatch": { @@ -7563,9 +7632,9 @@ "dev": true }, "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", "dev": true }, "object-keys": { @@ -7607,14 +7676,14 @@ } }, "object.values": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", - "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", + "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", "dev": true, "requires": { + "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", + "es-abstract": "^1.18.0-next.1", "has": "^1.0.3" } }, @@ -8026,6 +8095,12 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", @@ -8525,9 +8600,9 @@ "dev": true }, "postcss-reporter": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.1.tgz", - "integrity": "sha512-R9AK80KIqqMb+lwGRBcRkXS7r96VCTxrZvvrfibyA/dWjqctwx7leHMCC05A9HbW8PnChwOWwrmISwp5HQu5wg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.2.tgz", + "integrity": "sha512-JyQ96NTQQsso42y6L1H1RqHfWH1C3Jr0pt91mVv5IdYddZAE9DUZxuferNgk6q0o6vBVOrfVJb10X1FgDzjmDw==", "dev": true, "requires": { "colorette": "^1.2.1", @@ -8535,8 +8610,7 @@ "lodash.forown": "^4.4.0", "lodash.get": "^4.4.2", "lodash.groupby": "^4.6.0", - "lodash.sortby": "^4.7.0", - "log-symbols": "^4.0.0" + "lodash.sortby": "^4.7.0" } }, "postcss-resolve-nested-selector": { @@ -8727,6 +8801,16 @@ "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", "dev": true }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -9198,9 +9282,9 @@ } }, "rollup": { - "version": "2.33.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.33.3.tgz", - "integrity": "sha512-RpayhPTe4Gu/uFGCmk7Gp5Z9Qic2VsqZ040G+KZZvsZYdcuWaJg678JeDJJvJeEQXminu24a2au+y92CUWVd+w==", + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.34.0.tgz", + "integrity": "sha512-dW5iLvttZzdVehjEuNJ1bWvuMEJjOWGmnuFS82WeKHTGXDkRHQeq/ExdifkSyJv9dLcR86ysKRmrIDyR6O0X8g==", "dev": true, "requires": { "fsevents": "~2.1.2" @@ -9957,9 +10041,9 @@ } }, "spdx-license-ids": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", - "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", "dev": true }, "specificity": { @@ -10090,28 +10174,6 @@ "call-bind": "^1.0.0", "define-properties": "^1.1.3", "es-abstract": "^1.18.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } } }, "string.prototype.trimend": { @@ -11123,9 +11185,9 @@ } }, "unist-util-is": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.3.tgz", - "integrity": "sha512-bTofCFVx0iQM8Jqb1TBDVRIQW03YkD3p66JOd/aCWuqzlLyUtx1ZAGw/u+Zw+SttKvSVcvTiKYbfrtLoLefykw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.4.tgz", + "integrity": "sha512-3dF39j/u423v4BBQrk1AQ2Ve1FxY5W3JKwXxVFzBODQ6WEvccguhgp802qQLKSnxPODE6WuRZtV+ohlUg4meBA==", "dev": true }, "unist-util-stringify-position": { @@ -11368,6 +11430,12 @@ "spdx-expression-parse": "^3.0.0" } }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, "vfile": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.0.tgz", @@ -11593,9 +11661,9 @@ "dev": true }, "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", "dev": true }, "yallist": { diff --git a/package.json b/package.json index b4545406c..30b34ba6b 100644 --- a/package.json +++ b/package.json @@ -94,12 +94,12 @@ }, "devDependencies": { "@babel/cli": "^7.12.8", - "@babel/core": "^7.12.8", + "@babel/core": "^7.12.9", "@babel/preset-env": "^7.12.7", - "@rollup/plugin-babel": "^5.2.1", - "@rollup/plugin-commonjs": "^16.0.0", - "@rollup/plugin-node-resolve": "^10.0.0", - "autoprefixer": "^10.0.2", + "@rollup/plugin-babel": "^5.2.2", + "@rollup/plugin-commonjs": "^17.0.0", + "@rollup/plugin-node-resolve": "^11.0.0", + "autoprefixer": "^10.0.4", "bundlewatch": "^0.3.1", "clean-css-cli": "^4.3.0", "cross-env": "^7.0.2", @@ -110,7 +110,7 @@ "find-unused-sass-variables": "^3.0.0", "glob": "^7.1.6", "hammer-simulator": "0.0.1", - "hugo-bin": "^0.66.2", + "hugo-bin": "^0.67.0", "ip": "^1.1.5", "jquery": "^3.5.1", "karma": "^5.2.3", @@ -122,14 +122,14 @@ "karma-jasmine": "^4.0.1", "karma-jasmine-html-reporter": "^1.5.4", "karma-rollup-preprocessor": "^7.0.5", - "linkinator": "^2.2.2", + "linkinator": "^2.4.0", "lockfile-lint": "^4.3.7", "nodemon": "^2.0.6", "npm-run-all": "^4.1.5", "popper.js": "^1.16.1", "postcss": "^8.1.10", "postcss-cli": "^8.3.0", - "rollup": "^2.33.3", + "rollup": "^2.34.0", "rollup-plugin-istanbul": "^2.0.1", "sass": "^1.29.0", "shelljs": "^0.8.4", diff --git a/scss/_breadcrumb.scss b/scss/_breadcrumb.scss index b30668b5d..f1ab3e8b9 100644 --- a/scss/_breadcrumb.scss +++ b/scss/_breadcrumb.scss @@ -18,7 +18,7 @@ float: left; // Suppress inline spacings and underlining of the separator padding-right: $breadcrumb-item-padding-x; color: $breadcrumb-divider-color; - content: escape-svg($breadcrumb-divider); + content: var(--#{$variable-prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)); } } diff --git a/scss/_button-group.scss b/scss/_button-group.scss index 1571d1ea9..abb363a84 100644 --- a/scss/_button-group.scss +++ b/scss/_button-group.scss @@ -132,7 +132,7 @@ @include border-bottom-radius(0); } - > .btn:not(:first-child), + > .btn ~ .btn, > .btn-group:not(:first-child) > .btn { @include border-top-radius(0); } diff --git a/scss/_tables.scss b/scss/_tables.scss index 1b2db3008..506c60be0 100644 --- a/scss/_tables.scss +++ b/scss/_tables.scss @@ -4,7 +4,6 @@ .table { --#{$variable-prefix}table-bg: #{$table-bg}; - --#{$variable-prefix}table-accent-bg: transparent; --#{$variable-prefix}table-striped-color: #{$table-striped-color}; --#{$variable-prefix}table-striped-bg: #{$table-striped-bg}; --#{$variable-prefix}table-active-color: #{$table-active-color}; diff --git a/scss/_variables.scss b/scss/_variables.scss index 98ca77e41..777955175 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -1245,15 +1245,15 @@ $figure-caption-color: $gray-600 !default; // Breadcrumbs $breadcrumb-font-size: null !default; -$breadcrumb-padding-y: $spacer / 2 !default; -$breadcrumb-padding-x: $spacer !default; +$breadcrumb-padding-y: 0 !default; +$breadcrumb-padding-x: 0 !default; $breadcrumb-item-padding-x: .5rem !default; $breadcrumb-margin-bottom: 1rem !default; -$breadcrumb-bg: $gray-200 !default; +$breadcrumb-bg: null !default; $breadcrumb-divider-color: $gray-600 !default; $breadcrumb-active-color: $gray-600 !default; $breadcrumb-divider: quote("/") !default; -$breadcrumb-border-radius: $border-radius !default; +$breadcrumb-border-radius: null !default; // Carousel diff --git a/site/content/docs/5.0/components/breadcrumb.md b/site/content/docs/5.0/components/breadcrumb.md index a6e953bb5..893f1f009 100644 --- a/site/content/docs/5.0/components/breadcrumb.md +++ b/site/content/docs/5.0/components/breadcrumb.md @@ -3,10 +3,13 @@ layout: docs title: Breadcrumb description: Indicate the current page's location within a navigational hierarchy that automatically adds separators via CSS. group: components +toc: true --- ## Example +Use an ordered or unordered list with linked list items to create a minimally styled breadcrumb. Use our utilities to add additional styles as desired. + {{< example >}} {{< /example >}} -## Changing the separator +## Dividers -Separators are automatically added in CSS through [`::before`](https://developer.mozilla.org/en-US/docs/Web/CSS/::before) and [`content`](https://developer.mozilla.org/en-US/docs/Web/CSS/content). They can be changed by changing `$breadcrumb-divider`. The [quote](https://sass-lang.com/documentation/modules/string#quote) function is needed to generate the quotes around a string, so if you want `>` as separator, you can use this: +Dividers are automatically added in CSS through [`::before`](https://developer.mozilla.org/en-US/docs/Web/CSS/::before) and [`content`](https://developer.mozilla.org/en-US/docs/Web/CSS/content). They can be changed by modifying a local CSS custom property `--bs-breadcrumb-divider`, or through the `$breadcrumb-divider` Sass variable. We default to our Sass variable, which is set as a fallback to the custom property. This way, you get a global divider that you can override without recompiling CSS at any time. + +{{< example >}} + +{{< /example >}} + +When modifying via Sass, the [quote](https://sass-lang.com/documentation/modules/string#quote) function is required to generate the quotes around a string. For example, using `>` as the divider, you can use this: ```scss $breadcrumb-divider: quote(">"); ``` -It's also possible to use an **embedded SVG icon**: +It's also possible to use an **embedded SVG icon**. Apply it via our CSS custom property, or use the Sass variable. + +{{< example >}} + +{{< /example >}} ```scss $breadcrumb-divider: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath d='M2.5 0L1 1.5 3.5 4 1 6.5 2.5 8l4-4-4-4z' fill='currentColor'/%3E%3C/svg%3E"); ``` -The separator can be removed by setting `$breadcrumb-divider` to `none`: +You can also remove the divider setting `--bs-breadcrumb-divider: '';` (empty strings in CSS custom properties counts as a value), or setting the Sass variable to `$breadcrumb-divider: none;`. + +{{< example >}} + +{{< /example >}} + ```scss $breadcrumb-divider: none; diff --git a/site/content/docs/5.0/components/modal.md b/site/content/docs/5.0/components/modal.md index 5bd116c8e..36dc3b548 100644 --- a/site/content/docs/5.0/components/modal.md +++ b/site/content/docs/5.0/components/modal.md @@ -877,12 +877,6 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap true Puts the focus on the modal when initialized. - - show - boolean - true - Shows the modal when initialized. - diff --git a/site/content/docs/5.0/content/typography.md b/site/content/docs/5.0/content/typography.md index b8e4f558a..d93702eea 100644 --- a/site/content/docs/5.0/content/typography.md +++ b/site/content/docs/5.0/content/typography.md @@ -13,7 +13,7 @@ Bootstrap sets basic global display, typography, and link styles. When more cont - Use a [native font stack]({{< docsref "/content/reboot#native-font-stack" >}}) that selects the best `font-family` for each OS and device. - For a more inclusive and accessible type scale, we use the browser's default root `font-size` (typically 16px) so visitors can customize their browser defaults as needed. - Use the `$font-family-base`, `$font-size-base`, and `$line-height-base` attributes as our typographic base applied to the ``. -- Set the global link color via `$link-color` and apply link underlines only on `:hover`. +- Set the global link color via `$link-color`. - Use `$body-bg` to set a `background-color` on the `` (`#fff` by default). These styles can be found within `_reboot.scss`, and the global variables are defined in `_variables.scss`. Make sure to set `$font-size-base` in `rem`. diff --git a/site/content/docs/5.0/migration.md b/site/content/docs/5.0/migration.md index dab1bd7df..7691d20c1 100644 --- a/site/content/docs/5.0/migration.md +++ b/site/content/docs/5.0/migration.md @@ -17,6 +17,13 @@ toc: true - Renamed `scale-color()` function to `shift-color()` to avoid collision with Sass's own color scaling function. +### Components + +#### Breadcrumbs + +- Simplified the default appearance of breadcrumbs by removing `padding`, `background-color`, and `border-radius`. +- Added new CSS custom property `--bs-breadcrumb-divider` for easy customization without needing to recompile CSS. + ## v5.0.0-alpha3 ### Browser support @@ -267,6 +274,7 @@ Changes to Reboot, typography, tables, and more. - Removed individual `$display-*-weight` variables for a single `$display-font-weight`. - Added two new `.display-*` heading styles, `.display-5` and `.display-6`. - Resized existing display headings for a slightly more consistent set of `font-size`s. +- Links are underlined by default (not just on hover), unless they're part of specific components. ### Forms