From c21506d499c682ea5e31107ce264b224c4bb644d Mon Sep 17 00:00:00 2001 From: Sascha Date: Sun, 1 Nov 2020 14:32:36 +0100 Subject: [PATCH 01/29] Fix TypeError when Bootstrap is included in `head` (#32024) * extend jquery after domContentLoaded event is fired * add unittest for util onDOMContentLoaded * wait for trigger jquery event after domContentLoaded * remove domcontentready from eventHandler * move istanbul ignore statements to correct line Co-authored-by: XhmikosR --- js/src/alert.js | 24 +++++++++++++----------- js/src/button.js | 26 ++++++++++++++------------ js/src/carousel.js | 25 ++++++++++++++----------- js/src/collapse.js | 25 ++++++++++++++----------- js/src/dom/event-handler.js | 2 +- js/src/dropdown.js | 25 ++++++++++++++----------- js/src/modal.js | 25 ++++++++++++++----------- js/src/popover.js | 26 ++++++++++++++------------ js/src/scrollspy.js | 25 ++++++++++++++----------- js/src/tab.js | 25 ++++++++++++++----------- js/src/toast.js | 25 ++++++++++++++----------- js/src/tooltip.js | 25 ++++++++++++++----------- js/src/util/index.js | 13 +++++++++++-- js/tests/unit/util/index.spec.js | 19 +++++++++++++++++++ 14 files changed, 184 insertions(+), 126 deletions(-) diff --git a/js/src/alert.js b/js/src/alert.js index b337fbc57..f3b4245af 100644 --- a/js/src/alert.js +++ b/js/src/alert.js @@ -7,6 +7,7 @@ import { getjQuery, + onDOMContentLoaded, TRANSITION_END, emulateTransitionEnd, getElementFromSelector, @@ -146,8 +147,6 @@ class Alert { */ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DISMISS, Alert.handleDismiss(new Alert())) -const $ = getjQuery() - /** * ------------------------------------------------------------------------ * jQuery @@ -155,15 +154,18 @@ const $ = getjQuery() * add .alert to jQuery only if jQuery is present */ -/* istanbul ignore if */ -if ($) { - const JQUERY_NO_CONFLICT = $.fn[NAME] - $.fn[NAME] = Alert.jQueryInterface - $.fn[NAME].Constructor = Alert - $.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Alert.jQueryInterface +onDOMContentLoaded(() => { + const $ = getjQuery() + /* istanbul ignore if */ + if ($) { + const JQUERY_NO_CONFLICT = $.fn[NAME] + $.fn[NAME] = Alert.jQueryInterface + $.fn[NAME].Constructor = Alert + $.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Alert.jQueryInterface + } } -} +}) export default Alert diff --git a/js/src/button.js b/js/src/button.js index f80b5e28c..c520aa117 100644 --- a/js/src/button.js +++ b/js/src/button.js @@ -5,7 +5,7 @@ * -------------------------------------------------------------------------- */ -import { getjQuery } from './util/index' +import { getjQuery, onDOMContentLoaded } from './util/index' import Data from './dom/data' import EventHandler from './dom/event-handler' @@ -97,24 +97,26 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => { data.toggle() }) -const $ = getjQuery() - /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .button to jQuery only if jQuery is present */ -/* istanbul ignore if */ -if ($) { - const JQUERY_NO_CONFLICT = $.fn[NAME] - $.fn[NAME] = Button.jQueryInterface - $.fn[NAME].Constructor = Button - $.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Button.jQueryInterface +onDOMContentLoaded(() => { + const $ = getjQuery() + /* istanbul ignore if */ + if ($) { + const JQUERY_NO_CONFLICT = $.fn[NAME] + $.fn[NAME] = Button.jQueryInterface + $.fn[NAME].Constructor = Button + + $.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Button.jQueryInterface + } } -} +}) export default Button diff --git a/js/src/carousel.js b/js/src/carousel.js index ed8e2b89a..b9bb50436 100644 --- a/js/src/carousel.js +++ b/js/src/carousel.js @@ -7,6 +7,7 @@ import { getjQuery, + onDOMContentLoaded, TRANSITION_END, emulateTransitionEnd, getElementFromSelector, @@ -611,23 +612,25 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => { } }) -const $ = getjQuery() - /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .carousel to jQuery only if jQuery is present */ -/* istanbul ignore if */ -if ($) { - const JQUERY_NO_CONFLICT = $.fn[NAME] - $.fn[NAME] = Carousel.jQueryInterface - $.fn[NAME].Constructor = Carousel - $.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Carousel.jQueryInterface + +onDOMContentLoaded(() => { + const $ = getjQuery() + /* istanbul ignore if */ + if ($) { + const JQUERY_NO_CONFLICT = $.fn[NAME] + $.fn[NAME] = Carousel.jQueryInterface + $.fn[NAME].Constructor = Carousel + $.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Carousel.jQueryInterface + } } -} +}) export default Carousel diff --git a/js/src/collapse.js b/js/src/collapse.js index f90238bc5..7788d0025 100644 --- a/js/src/collapse.js +++ b/js/src/collapse.js @@ -7,6 +7,7 @@ import { getjQuery, + onDOMContentLoaded, TRANSITION_END, emulateTransitionEnd, getSelectorFromElement, @@ -408,23 +409,25 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function ( }) }) -const $ = getjQuery() - /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .collapse to jQuery only if jQuery is present */ -/* istanbul ignore if */ -if ($) { - const JQUERY_NO_CONFLICT = $.fn[NAME] - $.fn[NAME] = Collapse.jQueryInterface - $.fn[NAME].Constructor = Collapse - $.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Collapse.jQueryInterface + +onDOMContentLoaded(() => { + const $ = getjQuery() + /* istanbul ignore if */ + if ($) { + const JQUERY_NO_CONFLICT = $.fn[NAME] + $.fn[NAME] = Collapse.jQueryInterface + $.fn[NAME].Constructor = Collapse + $.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Collapse.jQueryInterface + } } -} +}) export default Collapse diff --git a/js/src/dom/event-handler.js b/js/src/dom/event-handler.js index dced8d9de..1d109c57e 100644 --- a/js/src/dom/event-handler.js +++ b/js/src/dom/event-handler.js @@ -14,7 +14,6 @@ import { defaultPreventedPreservedOnDispatch } from './polyfill' * ------------------------------------------------------------------------ */ -const $ = getjQuery() const namespaceRegex = /[^.]*(?=\..*)\.|.*/ const stripNameRegex = /\..*/ const stripUidRegex = /::\d+$/ @@ -272,6 +271,7 @@ const EventHandler = { return null } + const $ = getjQuery() const typeEvent = event.replace(stripNameRegex, '') const inNamespace = event !== typeEvent const isNative = nativeEvents.indexOf(typeEvent) > -1 diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 28d8b7299..46311ee8a 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -7,6 +7,7 @@ import { getjQuery, + onDOMContentLoaded, getElementFromSelector, isElement, isVisible, @@ -512,23 +513,25 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function ( }) EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, e => e.stopPropagation()) -const $ = getjQuery() - /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .dropdown to jQuery only if jQuery is present */ -/* istanbul ignore if */ -if ($) { - const JQUERY_NO_CONFLICT = $.fn[NAME] - $.fn[NAME] = Dropdown.jQueryInterface - $.fn[NAME].Constructor = Dropdown - $.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Dropdown.jQueryInterface + +onDOMContentLoaded(() => { + const $ = getjQuery() + /* istanbul ignore if */ + if ($) { + const JQUERY_NO_CONFLICT = $.fn[NAME] + $.fn[NAME] = Dropdown.jQueryInterface + $.fn[NAME].Constructor = Dropdown + $.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Dropdown.jQueryInterface + } } -} +}) export default Dropdown diff --git a/js/src/modal.js b/js/src/modal.js index 4c1db3d5c..adddb62e2 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -7,6 +7,7 @@ import { getjQuery, + onDOMContentLoaded, TRANSITION_END, emulateTransitionEnd, getElementFromSelector, @@ -607,23 +608,25 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function ( data.show(this) }) -const $ = getjQuery() - /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .modal to jQuery only if jQuery is present */ -/* istanbul ignore if */ -if ($) { - const JQUERY_NO_CONFLICT = $.fn[NAME] - $.fn[NAME] = Modal.jQueryInterface - $.fn[NAME].Constructor = Modal - $.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Modal.jQueryInterface + +onDOMContentLoaded(() => { + const $ = getjQuery() + /* istanbul ignore if */ + if ($) { + const JQUERY_NO_CONFLICT = $.fn[NAME] + $.fn[NAME] = Modal.jQueryInterface + $.fn[NAME].Constructor = Modal + $.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Modal.jQueryInterface + } } -} +}) export default Modal diff --git a/js/src/popover.js b/js/src/popover.js index 54abe1f96..a4980a19e 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -5,7 +5,7 @@ * -------------------------------------------------------------------------- */ -import { getjQuery } from './util/index' +import { getjQuery, onDOMContentLoaded } from './util/index' import Data from './dom/data' import SelectorEngine from './dom/selector-engine' import Tooltip from './tooltip' @@ -167,22 +167,24 @@ class Popover extends Tooltip { } } -const $ = getjQuery() - /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ */ -/* istanbul ignore if */ -if ($) { - const JQUERY_NO_CONFLICT = $.fn[NAME] - $.fn[NAME] = Popover.jQueryInterface - $.fn[NAME].Constructor = Popover - $.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Popover.jQueryInterface + +onDOMContentLoaded(() => { + const $ = getjQuery() + /* istanbul ignore if */ + if ($) { + const JQUERY_NO_CONFLICT = $.fn[NAME] + $.fn[NAME] = Popover.jQueryInterface + $.fn[NAME].Constructor = Popover + $.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Popover.jQueryInterface + } } -} +}) export default Popover diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js index d37ca923d..a0061b7e1 100644 --- a/js/src/scrollspy.js +++ b/js/src/scrollspy.js @@ -7,6 +7,7 @@ import { getjQuery, + onDOMContentLoaded, getSelectorFromElement, getUID, isElement, @@ -317,22 +318,24 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => { .forEach(spy => new ScrollSpy(spy, Manipulator.getDataAttributes(spy))) }) -const $ = getjQuery() - /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ */ -/* istanbul ignore if */ -if ($) { - const JQUERY_NO_CONFLICT = $.fn[NAME] - $.fn[NAME] = ScrollSpy.jQueryInterface - $.fn[NAME].Constructor = ScrollSpy - $.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return ScrollSpy.jQueryInterface + +onDOMContentLoaded(() => { + const $ = getjQuery() + /* istanbul ignore if */ + if ($) { + const JQUERY_NO_CONFLICT = $.fn[NAME] + $.fn[NAME] = ScrollSpy.jQueryInterface + $.fn[NAME].Constructor = ScrollSpy + $.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return ScrollSpy.jQueryInterface + } } -} +}) export default ScrollSpy diff --git a/js/src/tab.js b/js/src/tab.js index 76895b8dd..af0dfc97a 100644 --- a/js/src/tab.js +++ b/js/src/tab.js @@ -7,6 +7,7 @@ import { getjQuery, + onDOMContentLoaded, TRANSITION_END, emulateTransitionEnd, getElementFromSelector, @@ -235,23 +236,25 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function ( data.show() }) -const $ = getjQuery() - /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .tab to jQuery only if jQuery is present */ -/* istanbul ignore if */ -if ($) { - const JQUERY_NO_CONFLICT = $.fn[NAME] - $.fn[NAME] = Tab.jQueryInterface - $.fn[NAME].Constructor = Tab - $.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Tab.jQueryInterface + +onDOMContentLoaded(() => { + const $ = getjQuery() + /* istanbul ignore if */ + if ($) { + const JQUERY_NO_CONFLICT = $.fn[NAME] + $.fn[NAME] = Tab.jQueryInterface + $.fn[NAME].Constructor = Tab + $.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Tab.jQueryInterface + } } -} +}) export default Tab diff --git a/js/src/toast.js b/js/src/toast.js index 91eaba53f..308a5d879 100644 --- a/js/src/toast.js +++ b/js/src/toast.js @@ -7,6 +7,7 @@ import { getjQuery, + onDOMContentLoaded, TRANSITION_END, emulateTransitionEnd, getTransitionDurationFromElement, @@ -213,23 +214,25 @@ class Toast { } } -const $ = getjQuery() - /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .toast to jQuery only if jQuery is present */ -/* istanbul ignore if */ -if ($) { - const JQUERY_NO_CONFLICT = $.fn[NAME] - $.fn[NAME] = Toast.jQueryInterface - $.fn[NAME].Constructor = Toast - $.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Toast.jQueryInterface + +onDOMContentLoaded(() => { + const $ = getjQuery() + /* istanbul ignore if */ + if ($) { + const JQUERY_NO_CONFLICT = $.fn[NAME] + $.fn[NAME] = Toast.jQueryInterface + $.fn[NAME].Constructor = Toast + $.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Toast.jQueryInterface + } } -} +}) export default Toast diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 1203142ed..4d9d3c4a2 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -7,6 +7,7 @@ import { getjQuery, + onDOMContentLoaded, TRANSITION_END, emulateTransitionEnd, findShadowRoot, @@ -793,23 +794,25 @@ class Tooltip { } } -const $ = getjQuery() - /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .tooltip to jQuery only if jQuery is present */ -/* istanbul ignore if */ -if ($) { - const JQUERY_NO_CONFLICT = $.fn[NAME] - $.fn[NAME] = Tooltip.jQueryInterface - $.fn[NAME].Constructor = Tooltip - $.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Tooltip.jQueryInterface + +onDOMContentLoaded(() => { + const $ = getjQuery() + /* istanbul ignore if */ + if ($) { + const JQUERY_NO_CONFLICT = $.fn[NAME] + $.fn[NAME] = Tooltip.jQueryInterface + $.fn[NAME].Constructor = Tooltip + $.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Tooltip.jQueryInterface + } } -} +}) export default Tooltip diff --git a/js/src/util/index.js b/js/src/util/index.js index 457b2e027..0fd78c848 100644 --- a/js/src/util/index.js +++ b/js/src/util/index.js @@ -180,8 +180,15 @@ const getjQuery = () => { return null } +const onDOMContentLoaded = callback => { + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', callback) + } else { + callback() + } +} + export { - getjQuery, TRANSITION_END, getUID, getSelectorFromElement, @@ -194,5 +201,7 @@ export { isVisible, findShadowRoot, noop, - reflow + reflow, + getjQuery, + onDOMContentLoaded } diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js index 541c10baa..f7cc37977 100644 --- a/js/tests/unit/util/index.spec.js +++ b/js/tests/unit/util/index.spec.js @@ -394,4 +394,23 @@ describe('Util', () => { expect(Util.getjQuery()).toEqual(null) }) }) + + describe('onDOMContentLoaded', () => { + it('should execute callback when DOMContentLoaded is fired', () => { + const spy = jasmine.createSpy() + spyOnProperty(document, 'readyState').and.returnValue('loading') + Util.onDOMContentLoaded(spy) + window.document.dispatchEvent(new Event('DOMContentLoaded', { + bubbles: true, + cancelable: true + })) + expect(spy).toHaveBeenCalled() + }) + + it('should execute callback if readyState is not "loading"', () => { + const spy = jasmine.createSpy() + Util.onDOMContentLoaded(spy) + expect(spy).toHaveBeenCalled() + }) + }) }) From 421e2482e2a0a38dd821876957cade8e5e3d579d Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Sun, 1 Nov 2020 15:49:51 +0200 Subject: [PATCH 02/29] Streamline jQuery comment. (#32016) --- js/src/alert.js | 2 +- js/src/button.js | 2 +- js/src/carousel.js | 2 +- js/src/collapse.js | 2 +- js/src/dropdown.js | 2 +- js/src/modal.js | 2 +- js/src/popover.js | 1 + js/src/scrollspy.js | 1 + js/src/tab.js | 2 +- js/src/toast.js | 2 +- js/src/tooltip.js | 2 +- 11 files changed, 11 insertions(+), 9 deletions(-) diff --git a/js/src/alert.js b/js/src/alert.js index f3b4245af..d8c6a47b9 100644 --- a/js/src/alert.js +++ b/js/src/alert.js @@ -151,7 +151,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DISMISS, Alert.handleDi * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ - * add .alert to jQuery only if jQuery is present + * add .Alert to jQuery only if jQuery is present */ onDOMContentLoaded(() => { diff --git a/js/src/button.js b/js/src/button.js index c520aa117..a07c8c052 100644 --- a/js/src/button.js +++ b/js/src/button.js @@ -101,7 +101,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => { * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ - * add .button to jQuery only if jQuery is present + * add .Button to jQuery only if jQuery is present */ onDOMContentLoaded(() => { diff --git a/js/src/carousel.js b/js/src/carousel.js index b9bb50436..00724e662 100644 --- a/js/src/carousel.js +++ b/js/src/carousel.js @@ -616,7 +616,7 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => { * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ - * add .carousel to jQuery only if jQuery is present + * add .Carousel to jQuery only if jQuery is present */ onDOMContentLoaded(() => { diff --git a/js/src/collapse.js b/js/src/collapse.js index 7788d0025..838855f5f 100644 --- a/js/src/collapse.js +++ b/js/src/collapse.js @@ -413,7 +413,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function ( * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ - * add .collapse to jQuery only if jQuery is present + * add .Collapse to jQuery only if jQuery is present */ onDOMContentLoaded(() => { diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 46311ee8a..ac79ce04d 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -517,7 +517,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, e => e.stop * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ - * add .dropdown to jQuery only if jQuery is present + * add .Dropdown to jQuery only if jQuery is present */ onDOMContentLoaded(() => { diff --git a/js/src/modal.js b/js/src/modal.js index adddb62e2..c4d8cdd88 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -612,7 +612,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function ( * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ - * add .modal to jQuery only if jQuery is present + * add .Modal to jQuery only if jQuery is present */ onDOMContentLoaded(() => { diff --git a/js/src/popover.js b/js/src/popover.js index a4980a19e..81ba21bef 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -171,6 +171,7 @@ class Popover extends Tooltip { * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ + * add .Popover to jQuery only if jQuery is present */ onDOMContentLoaded(() => { diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js index a0061b7e1..5043b8ef8 100644 --- a/js/src/scrollspy.js +++ b/js/src/scrollspy.js @@ -322,6 +322,7 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => { * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ + * add .ScrollSpy to jQuery only if jQuery is present */ onDOMContentLoaded(() => { diff --git a/js/src/tab.js b/js/src/tab.js index af0dfc97a..969621cf5 100644 --- a/js/src/tab.js +++ b/js/src/tab.js @@ -240,7 +240,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function ( * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ - * add .tab to jQuery only if jQuery is present + * add .Tab to jQuery only if jQuery is present */ onDOMContentLoaded(() => { diff --git a/js/src/toast.js b/js/src/toast.js index 308a5d879..e38fb7dfc 100644 --- a/js/src/toast.js +++ b/js/src/toast.js @@ -218,7 +218,7 @@ class Toast { * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ - * add .toast to jQuery only if jQuery is present + * add .Toast to jQuery only if jQuery is present */ onDOMContentLoaded(() => { diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 4d9d3c4a2..7a62739e8 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -798,7 +798,7 @@ class Tooltip { * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ - * add .tooltip to jQuery only if jQuery is present + * add .Tooltip to jQuery only if jQuery is present */ onDOMContentLoaded(() => { From 59692ce8621f91f5b495221d24cc471e7a83abf4 Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Sun, 1 Nov 2020 15:52:24 +0200 Subject: [PATCH 03/29] karma: stop excluding polyfill.js from istanbul (#30740) --- js/src/dom/polyfill.js | 2 -- js/tests/karma.conf.js | 10 +++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/js/src/dom/polyfill.js b/js/src/dom/polyfill.js index 61e75eccd..ed982587b 100644 --- a/js/src/dom/polyfill.js +++ b/js/src/dom/polyfill.js @@ -1,5 +1,3 @@ -/* istanbul ignore file */ - /** * -------------------------------------------------------------------------- * Bootstrap (v5.0.0-alpha2): dom/polyfill.js diff --git a/js/tests/karma.conf.js b/js/tests/karma.conf.js index e87ee1cc7..688868b18 100644 --- a/js/tests/karma.conf.js +++ b/js/tests/karma.conf.js @@ -134,17 +134,17 @@ if (browserStack) { emitWarning: false, global: { statements: 90, - branches: 90, + branches: 89, functions: 90, lines: 90 }, each: { overrides: { 'js/src/dom/polyfill.js': { - statements: 39, - lines: 37, - branches: 19, - functions: 50 + statements: 30, + lines: 30, + branches: 8, + functions: 30 } } } From e0b8fcdf899aa1c25fe2ddf050452f7451ed0cdd Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Sun, 1 Nov 2020 16:31:11 +0200 Subject: [PATCH 04/29] ESLint: enable new-cap rule but ignore properties (#32036) --- .eslintrc.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index 59fe70f56..4c49fd0b1 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -25,7 +25,12 @@ "error", "always-multiline" ], - "new-cap": "off", + "new-cap": [ + "error", + { + "properties": false + } + ], "no-console": "error", "object-curly-spacing": [ "error", From 71010cb1e99c95619e71f271e941e7edb0c6ea37 Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Mon, 2 Nov 2020 14:42:40 +0200 Subject: [PATCH 05/29] tests: switch to using `toContain()` to check for substring presence (#32043) --- js/tests/unit/tooltip.spec.js | 2 +- js/tests/unit/util/sanitizer.spec.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index 3e5c91794..611fadfe1 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -317,7 +317,7 @@ describe('Tooltip', () => { expect(tooltipShown).toBeDefined() expect(tooltipEl.getAttribute('aria-describedby')).toEqual(tooltipShown.getAttribute('id')) - expect(tooltipShown.getAttribute('id').indexOf('tooltip') !== -1).toEqual(true) + expect(tooltipShown.getAttribute('id')).toContain('tooltip') done() }) diff --git a/js/tests/unit/util/sanitizer.spec.js b/js/tests/unit/util/sanitizer.spec.js index dcfad8436..395875d62 100644 --- a/js/tests/unit/util/sanitizer.spec.js +++ b/js/tests/unit/util/sanitizer.spec.js @@ -20,7 +20,7 @@ describe('Sanitizer', () => { const result = sanitizeHtml(template, DefaultAllowlist, null) - expect(result.indexOf('script') === -1).toEqual(true) + expect(result).not.toContain('script') }) it('should allow aria attributes and safe attributes', () => { @@ -32,8 +32,8 @@ describe('Sanitizer', () => { const result = sanitizeHtml(template, DefaultAllowlist, null) - expect(result.indexOf('aria-pressed') !== -1).toEqual(true) - expect(result.indexOf('class="test"') !== -1).toEqual(true) + expect(result).toContain('aria-pressed') + expect(result).toContain('class="test"') }) it('should remove tags not in allowlist', () => { @@ -45,7 +45,7 @@ describe('Sanitizer', () => { const result = sanitizeHtml(template, DefaultAllowlist, null) - expect(result.indexOf(' diff --git a/js/tests/visual/button.html b/js/tests/visual/button.html index 6908361a6..14cc20870 100644 --- a/js/tests/visual/button.html +++ b/js/tests/visual/button.html @@ -44,7 +44,6 @@ - diff --git a/js/tests/visual/carousel.html b/js/tests/visual/carousel.html index 5588d06da..44fdff818 100644 --- a/js/tests/visual/carousel.html +++ b/js/tests/visual/carousel.html @@ -45,7 +45,6 @@ - diff --git a/js/tests/visual/collapse.html b/js/tests/visual/collapse.html index e33148ac8..f36f73f7e 100644 --- a/js/tests/visual/collapse.html +++ b/js/tests/visual/collapse.html @@ -71,7 +71,6 @@ - diff --git a/js/tests/visual/dropdown.html b/js/tests/visual/dropdown.html index fffde819a..0816683be 100644 --- a/js/tests/visual/dropdown.html +++ b/js/tests/visual/dropdown.html @@ -210,7 +210,6 @@ - diff --git a/js/tests/visual/modal.html b/js/tests/visual/modal.html index eabc63318..13e93d154 100644 --- a/js/tests/visual/modal.html +++ b/js/tests/visual/modal.html @@ -206,7 +206,6 @@ - diff --git a/js/tests/visual/popover.html b/js/tests/visual/popover.html index c28c7ec2e..b6ca7dc24 100644 --- a/js/tests/visual/popover.html +++ b/js/tests/visual/popover.html @@ -32,7 +32,6 @@ - diff --git a/js/tests/visual/scrollspy.html b/js/tests/visual/scrollspy.html index 2ed553d5d..6da8a51bf 100644 --- a/js/tests/visual/scrollspy.html +++ b/js/tests/visual/scrollspy.html @@ -86,7 +86,6 @@

Ad leggings keytar, brunch id art party dolor labore.

- diff --git a/js/tests/visual/tab.html b/js/tests/visual/tab.html index 509401d0d..a221f971e 100644 --- a/js/tests/visual/tab.html +++ b/js/tests/visual/tab.html @@ -222,7 +222,6 @@ - diff --git a/js/tests/visual/toast.html b/js/tests/visual/toast.html index 13d32fab4..046c4345c 100644 --- a/js/tests/visual/toast.html +++ b/js/tests/visual/toast.html @@ -52,7 +52,6 @@ - diff --git a/js/tests/visual/tooltip.html b/js/tests/visual/tooltip.html index c06ac739b..14f704b93 100644 --- a/js/tests/visual/tooltip.html +++ b/js/tests/visual/tooltip.html @@ -70,7 +70,6 @@ - From f989f8fb3ae581e9814095f625b53df4cfa23e8a Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Tue, 3 Nov 2020 15:40:16 +0200 Subject: [PATCH 19/29] Tighten bundlewatch limits. --- .bundlewatch.config.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.bundlewatch.config.json b/.bundlewatch.config.json index 6e3c15a96..dd21b6d2f 100644 --- a/.bundlewatch.config.json +++ b/.bundlewatch.config.json @@ -30,31 +30,31 @@ }, { "path": "./dist/css/bootstrap.min.css", - "maxSize": "21.6 kB" + "maxSize": "21.5 kB" }, { "path": "./dist/js/bootstrap.bundle.js", - "maxSize": "51 kB" + "maxSize": "50 kB" }, { "path": "./dist/js/bootstrap.bundle.min.js", - "maxSize": "22.5 kB" + "maxSize": "22 kB" }, { "path": "./dist/js/bootstrap.esm.js", - "maxSize": "28 kB" + "maxSize": "27 kB" }, { "path": "./dist/js/bootstrap.esm.min.js", - "maxSize": "19 kB" + "maxSize": "18 kB" }, { "path": "./dist/js/bootstrap.js", - "maxSize": "29 kB" + "maxSize": "28 kB" }, { "path": "./dist/js/bootstrap.min.js", - "maxSize": "16 kB" + "maxSize": "15.5 kB" } ], "ci": { From 09a09387f4991e2af0e6c0f359d0568f48d136b4 Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Thu, 5 Nov 2020 08:56:02 -0800 Subject: [PATCH 20/29] Add keyboard shortcut to focus search field (#31702) * Documentation: Add slash key event to focus the input search. * Add little tag for keyboard shortcut in the search field * Use ctrl / as keyboard shortcut * Update search.js Co-authored-by: chuckrincon Co-authored-by: Patrick H. Lauke Co-authored-by: XhmikosR --- site/assets/js/search.js | 7 +++++++ site/assets/scss/_subnav.scss | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/site/assets/js/search.js b/site/assets/js/search.js index bb97c5cf8..823dcb10a 100644 --- a/site/assets/js/search.js +++ b/site/assets/js/search.js @@ -12,6 +12,13 @@ var inputElement = document.getElementById('search-input') var siteDocsVersion = inputElement.getAttribute('data-docs-version') + document.addEventListener('keydown', function (event) { + if (event.ctrlKey && event.key === '/') { + event.preventDefault() + inputElement.focus() + } + }) + function getOrigin() { var location = window.location var origin = location.origin diff --git a/site/assets/scss/_subnav.scss b/site/assets/scss/_subnav.scss index 566bc17fd..c23d96a49 100644 --- a/site/assets/scss/_subnav.scss +++ b/site/assets/scss/_subnav.scss @@ -25,9 +25,36 @@ } .bd-search { - .form-control:focus { - border-color: $bd-purple-bright; - box-shadow: 0 0 0 3px rgba($bd-purple-bright, .25); + position: relative; + + &::after { + position: absolute; + top: .4rem; + right: .4rem; + display: flex; + align-items: center; + justify-content: center; + height: 1.5rem; + padding-right: .25rem; + padding-left: .25rem; + @include font-size(.75rem); + color: $gray-600; + content: "Ctrl + /"; + border: $border-width solid $border-color; + @include border-radius(.125rem); + } + + @include media-breakpoint-down(md) { + width: 100%; + } + + .form-control { + padding-right: 3.75rem; + + &:focus { + border-color: $bd-purple-bright; + box-shadow: 0 0 0 3px rgba($bd-purple-bright, .25); + } } } From c1bb1acf54bb86c7ea8cbb2c5d81bdf960d50f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 6 Nov 2020 09:46:49 +0100 Subject: [PATCH 21/29] Remove firefox workaround for ::file-selector-button margin. (#32064) As per https://bugzilla.mozilla.org/show_bug.cgi?id=1673895, this workaround shouldn't be necessary in FF83+. Co-authored-by: XhmikosR --- scss/forms/_form-control.scss | 3 --- 1 file changed, 3 deletions(-) diff --git a/scss/forms/_form-control.scss b/scss/forms/_form-control.scss index 1fd1e1a8b..bac416f8c 100644 --- a/scss/forms/_form-control.scss +++ b/scss/forms/_form-control.scss @@ -78,7 +78,6 @@ padding: $input-padding-y $input-padding-x; margin: (-$input-padding-y) (-$input-padding-x); margin-inline-end: $input-padding-x; - -moz-margin-end: subtract($input-padding-x, 5px); // stylelint-disable-line property-no-vendor-prefix color: $form-file-button-color; @include gradient-bg($form-file-button-bg); pointer-events: none; @@ -156,7 +155,6 @@ padding: $input-padding-y-sm $input-padding-x-sm; margin: (-$input-padding-y-sm) (-$input-padding-x-sm); margin-inline-end: $input-padding-x-sm; - -moz-margin-end: subtract($input-padding-x-sm, 5px); // stylelint-disable-line property-no-vendor-prefix } &::-webkit-file-upload-button { @@ -177,7 +175,6 @@ padding: $input-padding-y-lg $input-padding-x-lg; margin: (-$input-padding-y-lg) (-$input-padding-x-lg); margin-inline-end: $input-padding-x-lg; - -moz-margin-end: subtract($input-padding-x-lg, 5px); // stylelint-disable-line property-no-vendor-prefix } &::-webkit-file-upload-button { From 82f24161320dc98fc529414e7cbf5d21e6f7616c Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Fri, 6 Nov 2020 12:00:03 +0200 Subject: [PATCH 22/29] stylelint: pass the ` --rd` flag (#32063) * stylelint: pass the ` --rd` flag Should report any needless disables * Update _button-group.scss * Update _floating-labels.scss --- package.json | 2 +- scss/_button-group.scss | 2 -- scss/forms/_floating-labels.scss | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/package.json b/package.json index c2047c73b..15170d720 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "css": "npm-run-all css-compile css-prefix css-minify", "css-compile": "sass --style expanded --source-map --embed-sources --no-error-css scss/:dist/css/", "css-lint": "npm-run-all --continue-on-error --parallel css-lint-*", - "css-lint-stylelint": "stylelint \"**/*.{css,scss}\" --cache --cache-location .cache/.stylelintcache", + "css-lint-stylelint": "stylelint \"**/*.{css,scss}\" --cache --cache-location .cache/.stylelintcache --rd", "css-lint-vars": "fusv scss/ site/assets/scss/", "css-minify": "cleancss --level 1 --format breakWith=lf --source-map --source-map-inline-sources --output dist/css/bootstrap.min.css dist/css/bootstrap.css && cleancss --level 1 --format breakWith=lf --source-map --source-map-inline-sources --output dist/css/bootstrap-grid.min.css dist/css/bootstrap-grid.css && cleancss --level 1 --format breakWith=lf --source-map --source-map-inline-sources --output dist/css/bootstrap-utilities.min.css dist/css/bootstrap-utilities.css && cleancss --level 1 --format breakWith=lf --source-map --source-map-inline-sources --output dist/css/bootstrap-reboot.min.css dist/css/bootstrap-reboot.css", "css-prefix": "npm-run-all --parallel css-prefix-*", diff --git a/scss/_button-group.scss b/scss/_button-group.scss index b15c6292e..1571d1ea9 100644 --- a/scss/_button-group.scss +++ b/scss/_button-group.scss @@ -1,5 +1,3 @@ -// stylelint-disable selector-no-qualifying-type - // Make the div behave like a button .btn-group, .btn-group-vertical { diff --git a/scss/forms/_floating-labels.scss b/scss/forms/_floating-labels.scss index 42e56f27b..8b2e2b8eb 100644 --- a/scss/forms/_floating-labels.scss +++ b/scss/forms/_floating-labels.scss @@ -1,5 +1,3 @@ -// stylelint-disable selector-no-vendor-prefix - .form-floating { position: relative; From f20335b6c1427e35aecf9a28b29629d83ec3f364 Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Fri, 6 Nov 2020 04:35:17 -0800 Subject: [PATCH 23/29] Add .d-grid to our display utilities (#32066) Co-authored-by: XhmikosR --- scss/_utilities.scss | 2 +- site/content/docs/5.0/utilities/display.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scss/_utilities.scss b/scss/_utilities.scss index 7c98e6f51..cf6d4c8c5 100644 --- a/scss/_utilities.scss +++ b/scss/_utilities.scss @@ -23,7 +23,7 @@ $utilities: map-merge( print: true, property: display, class: d, - values: inline inline-block block table table-row table-cell flex inline-flex none + values: inline inline-block block grid table table-row table-cell flex inline-flex none ), "shadow": ( property: box-shadow, diff --git a/site/content/docs/5.0/utilities/display.md b/site/content/docs/5.0/utilities/display.md index a62878fde..2d033ba85 100644 --- a/site/content/docs/5.0/utilities/display.md +++ b/site/content/docs/5.0/utilities/display.md @@ -25,6 +25,7 @@ Where *value* is one of: - `inline` - `inline-block` - `block` +- `grid` - `table` - `table-cell` - `table-row` @@ -135,6 +136,7 @@ Change the `display` value of elements when printing with our print display util - `.d-print-inline` - `.d-print-inline-block` - `.d-print-block` +- `.d-print-grid` - `.d-print-table` - `.d-print-table-row` - `.d-print-table-cell` From 6a3761254050222d80eda2926ad6b6946a8787aa Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Mon, 2 Nov 2020 21:36:51 +0200 Subject: [PATCH 24/29] Add dedicated accordion component based on Collapse JS --- .bundlewatch.config.json | 2 +- scss/_accordion.scss | 124 ++++++++++++++++++ scss/_card.scss | 27 ---- scss/_variables.scss | 27 ++++ scss/bootstrap.scss | 1 + site/content/docs/5.0/components/accordion.md | 106 +++++++++++++++ site/content/docs/5.0/components/alerts.md | 3 - site/content/docs/5.0/components/collapse.md | 52 -------- site/data/sidebar.yml | 1 + 9 files changed, 260 insertions(+), 83 deletions(-) create mode 100644 scss/_accordion.scss create mode 100644 site/content/docs/5.0/components/accordion.md diff --git a/.bundlewatch.config.json b/.bundlewatch.config.json index dd21b6d2f..3833ae9a6 100644 --- a/.bundlewatch.config.json +++ b/.bundlewatch.config.json @@ -30,7 +30,7 @@ }, { "path": "./dist/css/bootstrap.min.css", - "maxSize": "21.5 kB" + "maxSize": "21.75 kB" }, { "path": "./dist/js/bootstrap.bundle.js", diff --git a/scss/_accordion.scss b/scss/_accordion.scss new file mode 100644 index 000000000..53715274a --- /dev/null +++ b/scss/_accordion.scss @@ -0,0 +1,124 @@ +// +// Base styles +// + +.accordion-button { + display: flex; + align-items: center; + width: 100%; + padding: $accordion-button-padding-y $accordion-button-padding-x; + @include font-size($font-size-base); + color: $accordion-button-color; + background-color: $accordion-button-bg; + border: solid $accordion-border-color; + border-width: $accordion-border-width $accordion-border-width 0; + @include border-radius(0); + overflow-anchor: none; + + &:not(.collapsed) { + color: $accordion-button-active-color; + background-color: $accordion-button-active-bg; + + &::after { + background-image: escape-svg($accordion-button-active-icon); + transform: $accordion-icon-transform; + } + } + + // Accordion icon + &::after { + flex-shrink: 0; + width: $accordion-icon-width; + height: $accordion-icon-width; + margin-left: auto; + content: ""; + background-image: escape-svg($accordion-button-icon); + background-repeat: no-repeat; + background-size: $accordion-icon-width; + transform-origin: center center; + @include transition($accordion-icon-transition); + } + + &:focus { + position: relative; + outline: 0; + box-shadow: $btn-focus-box-shadow; + } +} + +.accordion-header { + margin-bottom: 0; +} + +.accordion-item { + @include border-radius($accordion-border-radius); + + &:last-of-type { + .accordion-button { + border-bottom-width: $accordion-border-width; + + // Only set a border-radius on the last item if the accordion is collapsed + &.collapsed { + @include border-bottom-radius($accordion-border-radius); + } + } + + .accordion-body { + border-width: 0 $accordion-border-width $accordion-border-width; + @include border-bottom-radius($accordion-border-radius); + } + } + + &:first-of-type { + .accordion-button { + @include border-top-radius($accordion-border-radius); + } + } +} + +.accordion-body { + padding: $accordion-body-padding-y $accordion-body-padding-x; + border: solid $accordion-border-color; + border-width: $accordion-border-width $accordion-border-width 0; +} + + +// Flush accordion items +// +// Remove borders and border-radius to keep accordion items edge-to-edge. + +.accordion-flush { + .accordion-button { + border-right: 0; + border-left: 0; + @include border-radius(0); + } + + .accordion-body { + border-width: 0; + } + + .accordion-item { + border-right-width: 0; + border-left-width: 0; + @include border-radius(0); + + &:first-of-type { + .accordion-button { + border-top-width: 0; + @include border-top-radius(0); + } + } + + &:last-of-type { + .accordion-button { + border-bottom-width: 0; + @include border-bottom-radius(0); + } + + .accordion-body { + border-width: 0; + } + } + } +} diff --git a/scss/_card.scss b/scss/_card.scss index a526ec143..9b0f4969a 100644 --- a/scss/_card.scss +++ b/scss/_card.scss @@ -213,30 +213,3 @@ } } } - - -// -// Accordion -// - -.accordion { - overflow-anchor: none; - - > .card { - overflow: hidden; - - &:not(:last-of-type) { - border-bottom: 0; - @include border-bottom-radius(0); - } - - &:not(:first-of-type) { - @include border-top-radius(0); - } - - > .card-header { - @include border-radius(0); - margin-bottom: -$card-border-width; - } - } -} diff --git a/scss/_variables.scss b/scss/_variables.scss index 781ec79a4..6c5a070f2 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -1014,6 +1014,33 @@ $card-img-overlay-padding: $spacer !default; $card-group-margin: $grid-gutter-width / 2 !default; +// Accordion +$accordion-padding-y: 1rem !default; +$accordion-padding-x: 1.25rem !default; +$accordion-color: $body-color !default; +$accordion-bg: transparent !default; +$accordion-border-width: $border-width !default; +$accordion-border-color: rgba($black, .125) !default; +$accordion-border-radius: $border-radius !default; + +$accordion-body-padding-y: $accordion-padding-y !default; +$accordion-body-padding-x: $accordion-padding-x !default; + +$accordion-button-padding-y: $accordion-padding-y !default; +$accordion-button-padding-x: $accordion-padding-x !default; +$accordion-button-color: $accordion-color !default; +$accordion-button-bg: $accordion-bg !default; +$accordion-button-active-bg: tint-color($component-active-bg, 90%) !default; +$accordion-button-active-color: $primary !default; + +$accordion-icon-width: 1.25rem !default; +$accordion-icon-color: $accordion-color !default; +$accordion-icon-active-color: $accordion-button-active-color !default; +$accordion-icon-transition: transform .2s ease-in-out !default; +$accordion-icon-transform: rotate(180deg) !default; + +$accordion-button-icon: url("data:image/svg+xml,") !default; +$accordion-button-active-icon: url("data:image/svg+xml,") !default; // Tooltips diff --git a/scss/bootstrap.scss b/scss/bootstrap.scss index c65caab6d..27514484c 100644 --- a/scss/bootstrap.scss +++ b/scss/bootstrap.scss @@ -28,6 +28,7 @@ @import "nav"; @import "navbar"; @import "card"; +@import "accordion"; @import "breadcrumb"; @import "pagination"; @import "badge"; diff --git a/site/content/docs/5.0/components/accordion.md b/site/content/docs/5.0/components/accordion.md new file mode 100644 index 000000000..9844cf868 --- /dev/null +++ b/site/content/docs/5.0/components/accordion.md @@ -0,0 +1,106 @@ +--- +layout: docs +title: Accordion +description: Build vertically collapsing accordions in combination with our Collapse JavaScript plugin. +group: components +aliases: + - "/components/" + - "/docs/5.0/components/" +toc: true +--- + +## How it works + +The accordion uses [collapse]({{< docsref "/components/collapse" >}}) internally to make it collapsible. To render an accordion that's expanded, add the `.open` class on the `.accordion`. + +{{< callout info >}} +{{< partial "callout-info-prefersreducedmotion.md" >}} +{{< /callout >}} + +## Example + +Click the accordions below to expand/collapse the accordion content. + +{{< example >}} +
+
+

+ +

+
+
+ This is the first item's accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow. +
+
+
+
+

+ +

+
+
+ This is the second item's accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow. +
+
+
+
+

+ +

+
+
+ This is the third item's accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow. +
+
+
+
+{{< /example >}} + +### Flush + +Add `.accordion-flush` to remove the default `background-color`, some borders, and some rounded corners to render accordions edge-to-edge with their parent container. + +{{< example class="bg-light" >}} +
+
+

+ +

+
+
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
+
+
+
+

+ +

+
+
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
+
+
+
+

+ +

+
+
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
+
+
+
+{{< /example >}} + +## Accessibility + +Please read the [collapse accessibility section]({{< docsref "/components/collapse#accessibility" >}}) for more information. diff --git a/site/content/docs/5.0/components/alerts.md b/site/content/docs/5.0/components/alerts.md index 3eecceea2..5c68a3d4c 100644 --- a/site/content/docs/5.0/components/alerts.md +++ b/site/content/docs/5.0/components/alerts.md @@ -3,9 +3,6 @@ layout: docs title: Alerts description: Provide contextual feedback messages for typical user actions with the handful of available and flexible alert messages. group: components -aliases: - - "/components/" - - "/docs/5.0/components/" toc: true --- diff --git a/site/content/docs/5.0/components/collapse.md b/site/content/docs/5.0/components/collapse.md index c460f6b9a..076c17289 100644 --- a/site/content/docs/5.0/components/collapse.md +++ b/site/content/docs/5.0/components/collapse.md @@ -69,58 +69,6 @@ Multiple ` - - - -
-
- Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. -
-
- -
-
-

- -

-
-
-
- Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. -
-
-
-
-
-

- -

-
-
-
- Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. -
-
-
- -{{< /example >}} - ## Accessibility Be sure to add `aria-expanded` to the control element. This attribute explicitly conveys the current state of the collapsible element tied to the control to screen readers and similar assistive technologies. If the collapsible element is closed by default, the attribute on the control element should have a value of `aria-expanded="false"`. If you've set the collapsible element to be open by default using the `show` class, set `aria-expanded="true"` on the control instead. The plugin will automatically toggle this attribute on the control based on whether or not the collapsible element has been opened or closed (via JavaScript, or because the user triggered another control element also tied to the same collapsible element). If the control element's HTML element is not a button (e.g., an `
` or `
`), the attribute `role="button"` should be added to the element. diff --git a/site/data/sidebar.yml b/site/data/sidebar.yml index 7ee35db95..a12db2550 100644 --- a/site/data/sidebar.yml +++ b/site/data/sidebar.yml @@ -53,6 +53,7 @@ - title: Components pages: + - title: Accordion - title: Alerts - title: Badge - title: Breadcrumb From 3df4dd15e407dce8bc665fc0140497312856ec47 Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Tue, 3 Nov 2020 12:56:24 -0800 Subject: [PATCH 25/29] Update relative position hack for layers Switches to slightly more verbose, but more consistent, z-index layering we use elsewhere (e.g., pagination). Doing this ensures we're not toggling position on and off, but rather z-index. --- scss/_accordion.scss | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scss/_accordion.scss b/scss/_accordion.scss index 53715274a..0990a15c6 100644 --- a/scss/_accordion.scss +++ b/scss/_accordion.scss @@ -3,6 +3,7 @@ // .accordion-button { + position: relative; display: flex; align-items: center; width: 100%; @@ -39,8 +40,12 @@ @include transition($accordion-icon-transition); } + &:hover { + z-index: 2; + } + &:focus { - position: relative; + z-index: 3; outline: 0; box-shadow: $btn-focus-box-shadow; } From d6a72c4e1bb1dafdb21e759e42c2e6aa574ade74 Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Tue, 3 Nov 2020 12:56:38 -0800 Subject: [PATCH 26/29] Remove default transform-origin per code review --- scss/_accordion.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/scss/_accordion.scss b/scss/_accordion.scss index 0990a15c6..479aad1cc 100644 --- a/scss/_accordion.scss +++ b/scss/_accordion.scss @@ -36,7 +36,6 @@ background-image: escape-svg($accordion-button-icon); background-repeat: no-repeat; background-size: $accordion-icon-width; - transform-origin: center center; @include transition($accordion-icon-transition); } From 4c1f807142d4ddd6b63ea56b148ec20a5ae194bc Mon Sep 17 00:00:00 2001 From: Martijn Cuppens Date: Thu, 5 Nov 2020 21:18:38 +0100 Subject: [PATCH 27/29] Fix missing border & add transitions --- scss/_accordion.scss | 63 +++++++++---------- scss/_variables.scss | 4 ++ site/content/docs/5.0/components/accordion.md | 12 ++-- 3 files changed, 40 insertions(+), 39 deletions(-) diff --git a/scss/_accordion.scss b/scss/_accordion.scss index 479aad1cc..a68aaa70e 100644 --- a/scss/_accordion.scss +++ b/scss/_accordion.scss @@ -11,10 +11,14 @@ @include font-size($font-size-base); color: $accordion-button-color; background-color: $accordion-button-bg; - border: solid $accordion-border-color; - border-width: $accordion-border-width $accordion-border-width 0; + border: $accordion-border-width solid $accordion-border-color; @include border-radius(0); overflow-anchor: none; + @include transition($accordion-transition); + + &.collapsed { + border-bottom-width: 0; + } &:not(.collapsed) { color: $accordion-button-active-color; @@ -45,8 +49,9 @@ &:focus { z-index: 3; + border-color: $accordion-button-focus-border-color; outline: 0; - box-shadow: $btn-focus-box-shadow; + box-shadow: $accordion-button-focus-box-shadow; } } @@ -55,35 +60,35 @@ } .accordion-item { - @include border-radius($accordion-border-radius); - - &:last-of-type { - .accordion-button { - border-bottom-width: $accordion-border-width; - - // Only set a border-radius on the last item if the accordion is collapsed - &.collapsed { - @include border-bottom-radius($accordion-border-radius); - } - } - - .accordion-body { - border-width: 0 $accordion-border-width $accordion-border-width; - @include border-bottom-radius($accordion-border-radius); - } - } - &:first-of-type { .accordion-button { @include border-top-radius($accordion-border-radius); } } + + &:last-of-type { + .accordion-button { + // Only set a border-radius on the last item if the accordion is collapsed + &.collapsed { + border-bottom-width: $accordion-border-width; + @include border-bottom-radius($accordion-border-radius); + } + } + + .accordion-collapse { + border-bottom-width: $accordion-border-width; + @include border-bottom-radius($accordion-border-radius); + } + } +} + +.accordion-collapse { + border: solid $accordion-border-color; + border-width: 0 $accordion-border-width; } .accordion-body { padding: $accordion-body-padding-y $accordion-body-padding-x; - border: solid $accordion-border-color; - border-width: $accordion-border-width $accordion-border-width 0; } @@ -98,15 +103,11 @@ @include border-radius(0); } - .accordion-body { + .accordion-collapse { border-width: 0; } .accordion-item { - border-right-width: 0; - border-left-width: 0; - @include border-radius(0); - &:first-of-type { .accordion-button { border-top-width: 0; @@ -115,14 +116,10 @@ } &:last-of-type { - .accordion-button { + .accordion-button.collapsed { border-bottom-width: 0; @include border-bottom-radius(0); } - - .accordion-body { - border-width: 0; - } } } } diff --git a/scss/_variables.scss b/scss/_variables.scss index 6c5a070f2..7773ebaf1 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -1030,9 +1030,13 @@ $accordion-button-padding-y: $accordion-padding-y !default; $accordion-button-padding-x: $accordion-padding-x !default; $accordion-button-color: $accordion-color !default; $accordion-button-bg: $accordion-bg !default; +$accordion-transition: $btn-transition, border-radius .15s ease !default; $accordion-button-active-bg: tint-color($component-active-bg, 90%) !default; $accordion-button-active-color: $primary !default; +$accordion-button-focus-border-color: $input-focus-border-color !default; +$accordion-button-focus-box-shadow: $btn-focus-box-shadow !default; + $accordion-icon-width: 1.25rem !default; $accordion-icon-color: $accordion-color !default; $accordion-icon-active-color: $accordion-button-active-color !default; diff --git a/site/content/docs/5.0/components/accordion.md b/site/content/docs/5.0/components/accordion.md index 9844cf868..1f08a7911 100644 --- a/site/content/docs/5.0/components/accordion.md +++ b/site/content/docs/5.0/components/accordion.md @@ -29,7 +29,7 @@ Click the accordions below to expand/collapse the accordion content. Accordion Item #1 -
+
This is the first item's accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.
@@ -41,7 +41,7 @@ Click the accordions below to expand/collapse the accordion content. Accordion Item #2 -
+
This is the second item's accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.
@@ -53,7 +53,7 @@ Click the accordions below to expand/collapse the accordion content. Accordion Item #3 -
+
This is the third item's accordion body. It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. These classes control the overall appearance, as well as the showing and hiding via CSS transitions. You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.
@@ -74,7 +74,7 @@ Add `.accordion-flush` to remove the default `background-color`, some borders, a Accordion Item #1 -
+
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
@@ -84,7 +84,7 @@ Add `.accordion-flush` to remove the default `background-color`, some borders, a Accordion Item #2 -
+
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
@@ -94,7 +94,7 @@ Add `.accordion-flush` to remove the default `background-color`, some borders, a Accordion Item #3 -
+
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
From 82ac087c4d0c73f2e470f82c933463aede3f1284 Mon Sep 17 00:00:00 2001 From: Martijn Cuppens Date: Thu, 5 Nov 2020 21:26:01 +0100 Subject: [PATCH 28/29] Shade color for better color contrast --- scss/_variables.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scss/_variables.scss b/scss/_variables.scss index 7773ebaf1..d1782f2c4 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -1032,7 +1032,7 @@ $accordion-button-color: $accordion-color !default; $accordion-button-bg: $accordion-bg !default; $accordion-transition: $btn-transition, border-radius .15s ease !default; $accordion-button-active-bg: tint-color($component-active-bg, 90%) !default; -$accordion-button-active-color: $primary !default; +$accordion-button-active-color: shade-color($primary, 10%) !default; $accordion-button-focus-border-color: $input-focus-border-color !default; $accordion-button-focus-box-shadow: $btn-focus-box-shadow !default; From bb6daab961c8698900e2d0c01e5793f9219334d9 Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Fri, 6 Nov 2020 11:00:11 +0200 Subject: [PATCH 29/29] _variables.scss: reorder SVG attributes This results in slightly better gzip compression --- scss/_variables.scss | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scss/_variables.scss b/scss/_variables.scss index d1782f2c4..de7656e91 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -814,7 +814,7 @@ $form-feedback-invalid-color: $danger !default; $form-feedback-icon-valid-color: $form-feedback-valid-color !default; $form-feedback-icon-valid: url("data:image/svg+xml,") !default; $form-feedback-icon-invalid-color: $form-feedback-invalid-color !default; -$form-feedback-icon-invalid: url("data:image/svg+xml,") !default; +$form-feedback-icon-invalid: url("data:image/svg+xml,") !default; // scss-docs-start form-validation-states $form-validation-states: ( @@ -1043,8 +1043,8 @@ $accordion-icon-active-color: $accordion-button-active-color !defaul $accordion-icon-transition: transform .2s ease-in-out !default; $accordion-icon-transform: rotate(180deg) !default; -$accordion-button-icon: url("data:image/svg+xml,") !default; -$accordion-button-active-icon: url("data:image/svg+xml,") !default; +$accordion-button-icon: url("data:image/svg+xml,") !default; +$accordion-button-active-icon: url("data:image/svg+xml,") !default; // Tooltips @@ -1281,8 +1281,8 @@ $carousel-caption-spacer: 1.25rem !default; $carousel-control-icon-width: 2rem !default; -$carousel-control-prev-icon-bg: url("data:image/svg+xml,") !default; -$carousel-control-next-icon-bg: url("data:image/svg+xml,") !default; +$carousel-control-prev-icon-bg: url("data:image/svg+xml,") !default; +$carousel-control-next-icon-bg: url("data:image/svg+xml,") !default; $carousel-transition-duration: .6s !default; $carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`) @@ -1311,7 +1311,7 @@ $btn-close-height: $btn-close-width !default; $btn-close-padding-x: .25em !default; $btn-close-padding-y: $btn-close-padding-x !default; $btn-close-color: $black !default; -$btn-close-bg: url("data:image/svg+xml,") !default; +$btn-close-bg: url("data:image/svg+xml,") !default; $btn-close-focus-shadow: $input-btn-focus-box-shadow !default; $btn-close-opacity: .5 !default; $btn-close-hover-opacity: .75 !default;