Merge branch 'main' into new-border-bg-utils

This commit is contained in:
XhmikosR 2020-11-06 15:10:19 +02:00 committed by GitHub
commit e3336b143e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
69 changed files with 1035 additions and 1166 deletions

View file

@ -5,7 +5,9 @@ last 1 major version
not dead
Chrome >= 60
Firefox >= 60
Edge >= 16
# needed since Legacy Edge still has usage; 79 was the first Chromium Edge version
# should be removed in the future when its usage drops or when it's moved to dead browsers
not Edge < 79
iOS >= 10
Safari >= 10
Android >= 6

View file

@ -30,31 +30,31 @@
},
{
"path": "./dist/css/bootstrap.min.css",
"maxSize": "21.6 kB"
"maxSize": "21.75 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": {

View file

@ -25,7 +25,12 @@
"error",
"always-multiline"
],
"new-cap": "off",
"new-cap": [
"error",
{
"properties": false
}
],
"no-console": "error",
"object-curly-spacing": [
"error",

View file

@ -26,7 +26,6 @@ const bsPlugins = {
Data: path.resolve(__dirname, '../js/src/dom/data.js'),
EventHandler: path.resolve(__dirname, '../js/src/dom/event-handler.js'),
Manipulator: path.resolve(__dirname, '../js/src/dom/manipulator.js'),
Polyfill: path.resolve(__dirname, '../js/src/dom/polyfill.js'),
SelectorEngine: path.resolve(__dirname, '../js/src/dom/selector-engine.js'),
Alert: path.resolve(__dirname, '../js/src/alert.js'),
Button: path.resolve(__dirname, '../js/src/button.js'),
@ -66,10 +65,7 @@ const getConfigByPluginKey = pluginKey => {
pluginKey === 'Sanitizer'
) {
return {
external: [bsPlugins.Polyfill],
globals: {
[bsPlugins.Polyfill]: 'Polyfill'
}
external: []
}
}
@ -138,7 +134,6 @@ const domObjects = [
'Data',
'EventHandler',
'Manipulator',
'Polyfill',
'SelectorEngine'
]

View file

@ -7,6 +7,7 @@
import {
getjQuery,
onDOMContentLoaded,
TRANSITION_END,
emulateTransitionEnd,
getElementFromSelector,
@ -146,24 +147,25 @@ class Alert {
*/
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DISMISS, Alert.handleDismiss(new Alert()))
const $ = getjQuery()
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .alert to jQuery only if jQuery is present
* 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

View file

@ -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
* 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

View file

@ -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
* 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

View file

@ -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
* 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

View file

@ -6,7 +6,6 @@
*/
import { getjQuery } from '../util/index'
import { defaultPreventedPreservedOnDispatch } from './polyfill'
/**
* ------------------------------------------------------------------------
@ -14,7 +13,6 @@ import { defaultPreventedPreservedOnDispatch } from './polyfill'
* ------------------------------------------------------------------------
*/
const $ = getjQuery()
const namespaceRegex = /[^.]*(?=\..*)\.|.*/
const stripNameRegex = /\..*/
const stripUidRegex = /::\d+$/
@ -272,6 +270,7 @@ const EventHandler = {
return null
}
const $ = getjQuery()
const typeEvent = event.replace(stripNameRegex, '')
const inNamespace = event !== typeEvent
const isNative = nativeEvents.indexOf(typeEvent) > -1
@ -314,12 +313,6 @@ const EventHandler = {
if (defaultPrevented) {
evt.preventDefault()
if (!defaultPreventedPreservedOnDispatch) {
Object.defineProperty(evt, 'defaultPrevented', {
get: () => true
})
}
}
if (nativeDispatch) {

View file

@ -1,82 +0,0 @@
/* istanbul ignore file */
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.0.0-alpha2): dom/polyfill.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import { getUID } from '../util/index'
let find = Element.prototype.querySelectorAll
let findOne = Element.prototype.querySelector
// MSEdge resets defaultPrevented flag upon dispatchEvent call if at least one listener is attached
const defaultPreventedPreservedOnDispatch = (() => {
const e = new CustomEvent('Bootstrap', {
cancelable: true
})
const element = document.createElement('div')
element.addEventListener('Bootstrap', () => null)
e.preventDefault()
element.dispatchEvent(e)
return e.defaultPrevented
})()
const scopeSelectorRegex = /:scope\b/
const supportsScopeQuery = (() => {
const element = document.createElement('div')
try {
element.querySelectorAll(':scope *')
} catch (_) {
return false
}
return true
})()
if (!supportsScopeQuery) {
find = function (selector) {
if (!scopeSelectorRegex.test(selector)) {
return this.querySelectorAll(selector)
}
const hasId = Boolean(this.id)
if (!hasId) {
this.id = getUID('scope')
}
let nodeList = null
try {
selector = selector.replace(scopeSelectorRegex, `#${this.id}`)
nodeList = this.querySelectorAll(selector)
} finally {
if (!hasId) {
this.removeAttribute('id')
}
}
return nodeList
}
findOne = function (selector) {
if (!scopeSelectorRegex.test(selector)) {
return this.querySelector(selector)
}
const matches = find.call(this, selector)
return matches[0] ? matches[0] : null
}
}
export {
find,
findOne,
defaultPreventedPreservedOnDispatch
}

View file

@ -5,8 +5,6 @@
* --------------------------------------------------------------------------
*/
import { find as findFn, findOne } from './polyfill'
/**
* ------------------------------------------------------------------------
* Constants
@ -21,11 +19,11 @@ const SelectorEngine = {
},
find(selector, element = document.documentElement) {
return [].concat(...findFn.call(element, selector))
return [].concat(...Element.prototype.querySelectorAll.call(element, selector))
},
findOne(selector, element = document.documentElement) {
return findOne.call(element, selector)
return Element.prototype.querySelector.call(element, selector)
},
children(element, selector) {

View file

@ -7,6 +7,7 @@
import {
getjQuery,
onDOMContentLoaded,
getElementFromSelector,
isElement,
isVisible,
@ -277,10 +278,9 @@ class Dropdown {
// Handle dropup
if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
placement = PLACEMENT_TOP
if (this._menu.classList.contains(CLASS_NAME_MENURIGHT)) {
placement = PLACEMENT_TOPEND
}
placement = this._menu.classList.contains(CLASS_NAME_MENURIGHT) ?
PLACEMENT_TOPEND :
PLACEMENT_TOP
} else if (parentDropdown.classList.contains(CLASS_NAME_DROPRIGHT)) {
placement = PLACEMENT_RIGHT
} else if (parentDropdown.classList.contains(CLASS_NAME_DROPLEFT)) {
@ -512,23 +512,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
* 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

View file

@ -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
* 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

View file

@ -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,25 @@ class Popover extends Tooltip {
}
}
const $ = getjQuery()
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .Popover to jQuery only if jQuery is present
*/
/* 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

View file

@ -7,6 +7,7 @@
import {
getjQuery,
onDOMContentLoaded,
getSelectorFromElement,
getUID,
isElement,
@ -317,22 +318,25 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
.forEach(spy => new ScrollSpy(spy, Manipulator.getDataAttributes(spy)))
})
const $ = getjQuery()
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .ScrollSpy to jQuery only if jQuery is present
*/
/* 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

View file

@ -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
* 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

View file

@ -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
* 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

View file

@ -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
* 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

View file

@ -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
}

View file

@ -23,13 +23,6 @@ const browsers = {
browser: 'Firefox',
browser_version: 'latest'
},
edgeWin10: {
base: 'BrowserStack',
os: 'Windows',
os_version: '10',
browser: 'Edge',
browser_version: '16'
},
chromeWin10: {
base: 'BrowserStack',
os: 'Windows',

View file

@ -134,19 +134,9 @@ 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
}
}
}
}
}

View file

@ -297,31 +297,31 @@ describe('EventHandler', () => {
EventHandler.trigger(subelement, 'click')
// first listeners called
expect(i === 2).toEqual(true)
expect(i).toEqual(2)
EventHandler.off(element, 'click', 'span', handler)
EventHandler.trigger(subelement, 'click')
// removed listener not called
expect(i === 2).toEqual(true)
expect(i).toEqual(2)
EventHandler.trigger(anchor, 'click')
// not removed listener called
expect(i === 3).toEqual(true)
expect(i).toEqual(3)
EventHandler.on(element, 'click', 'span', handler)
EventHandler.trigger(anchor, 'click')
EventHandler.trigger(subelement, 'click')
// listener re-registered
expect(i === 5).toEqual(true)
expect(i).toEqual(5)
EventHandler.off(element, 'click', 'span')
EventHandler.trigger(subelement, 'click')
// listener removed again
expect(i === 5).toEqual(true)
expect(i).toEqual(5)
})
})
})

View file

@ -56,7 +56,7 @@ describe('Manipulator', () => {
describe('getDataAttributes', () => {
it('should return empty object for null', () => {
expect(Manipulator.getDataAttributes(null), {})
expect(Manipulator.getDataAttributes(null)).toEqual({})
expect().nothing()
})

View file

@ -1320,8 +1320,8 @@ describe('Dropdown', () => {
triggerDropdown.dispatchEvent(keydown)
expect(document.activeElement.classList.contains('d-none')).toEqual(false, '.d-none not focused')
expect(document.activeElement.style.display === 'none').toEqual(false, '"display: none" not focused')
expect(document.activeElement.style.visibility === 'hidden').toEqual(false, '"visibility: hidden" not focused')
expect(document.activeElement.style.display).not.toBe('none', '"display: none" not focused')
expect(document.activeElement.style.visibility).not.toBe('hidden', '"visibility: hidden" not focused')
done()
})

View file

@ -637,7 +637,7 @@ describe('Modal', () => {
modalEl.addEventListener('shown.bs.modal', () => {
modalEl.click()
setTimeout(() => {
expect(modalEl.clientHeight === modalEl.scrollHeight).toEqual(true)
expect(modalEl.clientHeight).toEqual(modalEl.scrollHeight)
done()
}, 20)
})

View file

@ -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()
})

View file

@ -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()
})
})
})

View file

@ -20,7 +20,7 @@ describe('Sanitizer', () => {
const result = sanitizeHtml(template, DefaultAllowlist, null)
expect(result.indexOf('script') === -1).toEqual(true)
expect(result).not.toContain('href="javascript:alert(7)')
})
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('<script>') === -1).toEqual(true)
expect(result).not.toContain('<script>')
})
it('should not use native api to sanitize if a custom function passed', () => {

View file

@ -51,7 +51,6 @@
</div>
</div>
<script src="../../dist/dom/polyfill.js"></script>
<script src="../../dist/dom/event-handler.js"></script>
<script src="../../dist/dom/selector-engine.js"></script>
<script src="../../dist/dom/data.js"></script>

View file

@ -44,7 +44,6 @@
</div>
</div>
<script src="../../dist/dom/polyfill.js"></script>
<script src="../../dist/dom/event-handler.js"></script>
<script src="../../dist/dom/selector-engine.js"></script>
<script src="../../dist/dom/data.js"></script>

View file

@ -45,7 +45,6 @@
</div>
</div>
<script src="../../dist/dom/polyfill.js"></script>
<script src="../../dist/dom/event-handler.js"></script>
<script src="../../dist/dom/selector-engine.js"></script>
<script src="../../dist/dom/manipulator.js"></script>

View file

@ -71,7 +71,6 @@
</div>
</div>
<script src="../../dist/dom/polyfill.js"></script>
<script src="../../dist/dom/event-handler.js"></script>
<script src="../../dist/dom/selector-engine.js"></script>
<script src="../../dist/dom/manipulator.js"></script>

View file

@ -210,7 +210,6 @@
</div>
<script src="../../../node_modules/popper.js/dist/umd/popper.min.js"></script>
<script src="../../dist/dom/polyfill.js"></script>
<script src="../../dist/dom/event-handler.js"></script>
<script src="../../dist/dom/selector-engine.js"></script>
<script src="../../dist/dom/data.js"></script>

View file

@ -206,7 +206,6 @@
</div>
<script src="../../../node_modules/popper.js/dist/umd/popper.min.js"></script>
<script src="../../dist/dom/polyfill.js"></script>
<script src="../../dist/dom/event-handler.js"></script>
<script src="../../dist/dom/selector-engine.js"></script>
<script src="../../dist/dom/data.js"></script>

View file

@ -32,7 +32,6 @@
</div>
<script src="../../../node_modules/popper.js/dist/umd/popper.min.js"></script>
<script src="../../dist/dom/polyfill.js"></script>
<script src="../../dist/dom/event-handler.js"></script>
<script src="../../dist/dom/selector-engine.js"></script>
<script src="../../dist/dom/manipulator.js"></script>

View file

@ -86,7 +86,6 @@
<p>Ad leggings keytar, brunch id art party dolor labore.</p>
</div>
<script src="../../dist/dom/polyfill.js"></script>
<script src="../../dist/dom/data.js"></script>
<script src="../../dist/dom/event-handler.js"></script>
<script src="../../dist/dom/selector-engine.js"></script>

View file

@ -222,7 +222,6 @@
</div>
<script src="../../../node_modules/popper.js/dist/umd/popper.min.js"></script>
<script src="../../dist/dom/polyfill.js"></script>
<script src="../../dist/dom/event-handler.js"></script>
<script src="../../dist/dom/selector-engine.js"></script>
<script src="../../dist/dom/data.js"></script>

View file

@ -52,7 +52,6 @@
</div>
</div>
<script src="../../dist/dom/polyfill.js"></script>
<script src="../../dist/dom/event-handler.js"></script>
<script src="../../dist/dom/manipulator.js"></script>
<script src="../../dist/dom/data.js"></script>

View file

@ -70,7 +70,6 @@
</div>
<script src="../../../node_modules/popper.js/dist/umd/popper.min.js"></script>
<script src="../../dist/dom/polyfill.js"></script>
<script src="../../dist/dom/selector-engine.js"></script>
<script src="../../dist/dom/event-handler.js"></script>
<script src="../../dist/dom/manipulator.js"></script>

828
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -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-*",
@ -54,7 +54,7 @@
"docs-vnu": "node build/vnu-jar.js",
"docs-lint": "npm-run-all --parallel docs-vnu docs-linkinator",
"docs-serve": "hugo server --port 9001 --disableFastRender",
"docs-serve-only": "sirv _gh_pages --port 9001",
"docs-serve-only": "npx sirv-cli _gh_pages --port 9001",
"lockfile-lint": "lockfile-lint --allowed-hosts npm --allowed-schemes https: --empty-hostname false --type npm --path package-lock.json",
"update-deps": "ncu -u -x karma-browserstack-launcher,terser && npm update && echo Manually update site/assets/js/vendor",
"release": "npm-run-all dist release-sri docs-build release-zip*",
@ -109,7 +109,7 @@
"find-unused-sass-variables": "^3.0.0",
"glob": "^7.1.6",
"hammer-simulator": "0.0.1",
"hugo-bin": "^0.64.5",
"hugo-bin": "^0.65.0",
"ip": "^1.1.5",
"jquery": "^3.5.1",
"karma": "^5.2.3",
@ -117,22 +117,21 @@
"karma-chrome-launcher": "^3.1.0",
"karma-coverage-istanbul-reporter": "^3.0.3",
"karma-detect-browsers": "^2.3.3",
"karma-firefox-launcher": "^2.0.0",
"karma-firefox-launcher": "^2.1.0",
"karma-jasmine": "^4.0.1",
"karma-jasmine-html-reporter": "^1.5.4",
"karma-rollup-preprocessor": "^7.0.5",
"linkinator": "^2.2.0",
"linkinator": "^2.2.2",
"lockfile-lint": "^4.3.7",
"nodemon": "^2.0.6",
"npm-run-all": "^4.1.5",
"popper.js": "^1.16.1",
"postcss": "^8.1.4",
"postcss-cli": "^8.1.0",
"rollup": "^2.32.1",
"postcss-cli": "^8.2.0",
"rollup": "^2.33.1",
"rollup-plugin-istanbul": "^2.0.1",
"sass": "^1.27.1",
"sass": "^1.28.0",
"shelljs": "^0.8.4",
"sirv-cli": "^1.0.8",
"stylelint": "^13.7.2",
"stylelint-config-twbs-bootstrap": "^2.1.0",
"terser": "5.1.0",

125
scss/_accordion.scss Normal file
View file

@ -0,0 +1,125 @@
//
// Base styles
//
.accordion-button {
position: relative;
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: $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;
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;
@include transition($accordion-icon-transition);
}
&:hover {
z-index: 2;
}
&:focus {
z-index: 3;
border-color: $accordion-button-focus-border-color;
outline: 0;
box-shadow: $accordion-button-focus-box-shadow;
}
}
.accordion-header {
margin-bottom: 0;
}
.accordion-item {
&: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;
}
// 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-collapse {
border-width: 0;
}
.accordion-item {
&:first-of-type {
.accordion-button {
border-top-width: 0;
@include border-top-radius(0);
}
}
&:last-of-type {
.accordion-button.collapsed {
border-bottom-width: 0;
@include border-bottom-radius(0);
}
}
}
}

View file

@ -1,5 +1,3 @@
// stylelint-disable selector-no-qualifying-type
// Make the div behave like a button
.btn-group,
.btn-group-vertical {

View file

@ -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;
}
}
}

View file

@ -295,8 +295,6 @@ samp {
// 1. Remove browser default top margin
// 2. Reset browser default of `1em` to use `rem`s
// 3. Don't allow content to break outside
// 4. Disable auto-hiding scrollbar in legacy Edge to avoid overlap,
// making it impossible to interact with the content
pre {
display: block;
@ -305,7 +303,6 @@ pre {
overflow: auto; // 3
@include font-size($code-font-size);
color: $pre-color;
-ms-overflow-style: scrollbar; // 4
// Account for some code outputs that place code tags in pre tags
code {
@ -434,13 +431,6 @@ textarea {
line-height: inherit;
}
// Show the overflow in Edge
button,
input {
overflow: visible;
}
// Remove the inheritance of text transform in Firefox
button,
@ -516,8 +506,7 @@ fieldset {
// 1. By using `float: left`, the legend will behave like a block element.
// This way the border of a fieldset wraps around the legend if present.
// 2. Correct the text wrapping in Edge.
// 3. Fix wrapping bug.
// 2. Fix wrapping bug.
// See https://github.com/twbs/bootstrap/issues/29712
legend {
@ -528,10 +517,9 @@ legend {
@include font-size($legend-font-size);
font-weight: $legend-font-weight;
line-height: inherit;
white-space: normal; // 2
+ * {
clear: left; // 3
clear: left; // 2
}
}

View file

@ -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,

View file

@ -792,7 +792,7 @@ $form-range-thumb-transition: background-color .15s ease-in-out, bo
$form-file-button-color: $input-color !default;
$form-file-button-bg: $input-group-addon-bg !default;
$form-file-button-hover-bg: shade-color($input-group-addon-bg, 5%) !default;
$form-file-button-hover-bg: shade-color($form-file-button-bg, 5%) !default;
$form-floating-height: add(3.5rem, $input-height-border) !default;
$form-floating-padding-x: $input-padding-x !default;
@ -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,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/></svg>") !default;
$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default;
$form-feedback-icon-invalid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='#{$form-feedback-icon-invalid-color}' viewBox='0 0 12 12'><circle cx='6' cy='6' r='4.5'/><path stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/><circle cx='6' cy='8.2' r='.6' fill='#{$form-feedback-icon-invalid-color}' stroke='none'/></svg>") !default;
$form-feedback-icon-invalid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='#{$form-feedback-icon-invalid-color}'><circle cx='6' cy='6' r='4.5'/><path stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/><circle cx='6' cy='8.2' r='.6' fill='#{$form-feedback-icon-invalid-color}' stroke='none'/></svg>") !default;
// scss-docs-start form-validation-states
$form-validation-states: (
@ -1014,6 +1014,37 @@ $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-transition: $btn-transition, border-radius .15s ease !default;
$accordion-button-active-bg: tint-color($component-active-bg, 90%) !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;
$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,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-color}'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/></svg>") !default;
$accordion-button-active-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-active-color}'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/></svg>") !default;
// Tooltips
@ -1250,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,<svg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 16 16'><path d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/></svg>") !default;
$carousel-control-next-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 16 16'><path d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/></svg>") !default;
$carousel-control-prev-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$carousel-control-color}'><path d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/></svg>") !default;
$carousel-control-next-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$carousel-control-color}'><path d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/></svg>") !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`)
@ -1280,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,<svg xmlns='http://www.w3.org/2000/svg' fill='#{$btn-close-color}' viewBox='0 0 16 16'><path d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/></svg>") !default;
$btn-close-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$btn-close-color}'><path d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/></svg>") !default;
$btn-close-focus-shadow: $input-btn-focus-box-shadow !default;
$btn-close-opacity: .5 !default;
$btn-close-hover-opacity: .75 !default;

1
scss/bootstrap.scss vendored
View file

@ -28,6 +28,7 @@
@import "nav";
@import "navbar";
@import "card";
@import "accordion";
@import "breadcrumb";
@import "pagination";
@import "badge";

View file

@ -1,5 +1,3 @@
// stylelint-disable selector-no-vendor-prefix
.form-floating {
position: relative;
@ -61,25 +59,3 @@
}
// stylelint-enable no-duplicate-selectors
}
//
// Fallback for classic Edge
//
@supports (-ms-ime-align: auto) {
.form-floating {
display: flex;
flex-direction: column-reverse;
}
.form-floating > label {
position: static;
padding: 0;
margin-bottom: calc(#{$form-floating-padding-y} / 2); // stylelint-disable-line function-disallowed-list
border: 0;
@include transition(none);
}
.form-floating > .form-control::-ms-input-placeholder {
color: $input-placeholder-color;
}
}

View file

@ -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 {

View file

@ -18,7 +18,6 @@
// No box-shadow() mixin for focus accessibility.
&::-webkit-slider-thumb { box-shadow: $form-range-thumb-focus-box-shadow; }
&::-moz-range-thumb { box-shadow: $form-range-thumb-focus-box-shadow; }
&::-ms-thumb { box-shadow: $form-range-thumb-focus-box-shadow; }
}
&::-moz-focus-outer {
@ -78,46 +77,6 @@
@include box-shadow($form-range-track-box-shadow);
}
&::-ms-thumb {
width: $form-range-thumb-width;
height: $form-range-thumb-height;
margin-top: 0; // Edge specific
margin-right: $form-range-thumb-focus-box-shadow-width; // Workaround that overflowed box-shadow is hidden.
margin-left: $form-range-thumb-focus-box-shadow-width; // Workaround that overflowed box-shadow is hidden.
@include gradient-bg($form-range-thumb-bg);
border: $form-range-thumb-border;
@include border-radius($form-range-thumb-border-radius);
@include box-shadow($form-range-thumb-box-shadow);
@include transition($form-range-thumb-transition);
appearance: none;
&:active {
@include gradient-bg($form-range-thumb-active-bg);
}
}
&::-ms-track {
width: $form-range-track-width;
height: $form-range-track-height;
color: transparent;
cursor: $form-range-track-cursor;
background-color: transparent;
border-color: transparent;
border-width: $form-range-thumb-height / 2;
@include box-shadow($form-range-track-box-shadow);
}
&::-ms-fill-lower {
background-color: $form-range-track-bg;
@include border-radius($form-range-track-border-radius);
}
&::-ms-fill-upper {
margin-right: 15px; // arbitrary?
background-color: $form-range-track-bg;
@include border-radius($form-range-track-border-radius);
}
&:disabled {
pointer-events: none;
@ -128,9 +87,5 @@
&::-moz-range-thumb {
background-color: $form-range-thumb-disabled-bg;
}
&::-ms-thumb {
background-color: $form-range-thumb-disabled-bg;
}
}
}

View file

@ -32,16 +32,6 @@
// Avoid using mixin so we can pass custom focus shadow properly
box-shadow: $form-select-focus-box-shadow;
}
&::-ms-value {
// For visual consistency with other platforms/browsers,
// suppress the default white text on blue background highlight given to
// the selected option text when the (still closed) <select> receives focus
// in Edge.
// See https://github.com/twbs/bootstrap/issues/19398.
color: $input-color;
background-color: $input-bg;
}
}
&[multiple],

View file

@ -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

View file

@ -3,6 +3,7 @@
color: rgba($link-color, .5);
@include transition(color .15s ease-in-out);
&:focus,
&:hover {
color: $link-color;
text-decoration: none;

View file

@ -273,7 +273,6 @@
padding: 1rem;
margin-bottom: 1rem;
background-color: $gray-100;
-ms-overflow-style: -ms-autohiding-scrollbar;
@include media-breakpoint-up(sm) {
padding: 1rem 1.5rem;

View file

@ -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);
}
}
}

View file

@ -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 >}}
<div class="accordion" id="accordionExample">
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne">
<button class="accordion-button" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
Accordion Item #1
</button>
</h2>
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-parent="#accordionExample">
<div class="accordion-body">
<strong>This is the first item's accordion body.</strong> 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 <code>.accordion-body</code>, though the transition does limit overflow.
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingTwo">
<button class="accordion-button collapsed" type="button" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
Accordion Item #2
</button>
</h2>
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-parent="#accordionExample">
<div class="accordion-body">
<strong>This is the second item's accordion body.</strong> 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 <code>.accordion-body</code>, though the transition does limit overflow.
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingThree">
<button class="accordion-button collapsed" type="button" data-toggle="collapse" data-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
Accordion Item #3
</button>
</h2>
<div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree" data-parent="#accordionExample">
<div class="accordion-body">
<strong>This is the third item's accordion body.</strong> 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 <code>.accordion-body</code>, though the transition does limit overflow.
</div>
</div>
</div>
</div>
{{< /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" >}}
<div class="accordion accordion-flush" id="accordionFlushExample">
<div class="accordion-item">
<h2 class="accordion-header" id="flush-headingOne">
<button class="accordion-button collapsed" type="button" data-toggle="collapse" data-target="#flush-collapseOne" aria-expanded="false" aria-controls="flush-collapseOne">
Accordion Item #1
</button>
</h2>
<div id="flush-collapseOne" class="accordion-collapse collapse" aria-labelledby="flush-headingOne" data-parent="#accordionFlushExample">
<div class="accordion-body">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.</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="flush-headingTwo">
<button class="accordion-button collapsed" type="button" data-toggle="collapse" data-target="#flush-collapseTwo" aria-expanded="false" aria-controls="flush-collapseTwo">
Accordion Item #2
</button>
</h2>
<div id="flush-collapseTwo" class="accordion-collapse collapse" aria-labelledby="flush-headingTwo" data-parent="#accordionFlushExample">
<div class="accordion-body">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.</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="flush-headingThree">
<button class="accordion-button collapsed" type="button" data-toggle="collapse" data-target="#flush-collapseThree" aria-expanded="false" aria-controls="flush-collapseThree">
Accordion Item #3
</button>
</h2>
<div id="flush-collapseThree" class="accordion-collapse collapse" aria-labelledby="flush-headingThree" data-parent="#accordionFlushExample">
<div class="accordion-body">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.</div>
</div>
</div>
</div>
{{< /example >}}
## Accessibility
Please read the [collapse accessibility section]({{< docsref "/components/collapse#accessibility" >}}) for more information.

View file

@ -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
---

View file

@ -54,6 +54,10 @@ In need of a button, but not the hefty background colors they bring? Replace the
{{< /buttons.inline >}}
{{< /example >}}
{{< callout info >}}
Some of the button styles use a relatively light foreground color, and should only be used on a dark background in order to have sufficient contrast.
{{< /callout >}}
## Sizes
Fancy larger or smaller buttons? Add `.btn-lg` or `.btn-sm` for additional sizes.

View file

@ -69,58 +69,6 @@ Multiple `<button>` or `<a>` can show and hide an element if they each reference
</div>
{{< /example >}}
## Accordion example
Using the [card]({{< docsref "/components/card" >}}) component, you can extend the default collapse behavior to create an accordion. To properly achieve the accordion style, be sure to use `.accordion` as a wrapper.
{{< example >}}
<div class="accordion" id="accordionExample">
<div class="card">
<div class="card-header p-0" id="headingOne">
<h2 class="mb-0">
<button class="btn btn-light btn-block text-left p-3 rounded-0" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
Collapsible Group Item #1
</button>
</h2>
</div>
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordionExample">
<div class="card-body">
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.
</div>
</div>
</div>
<div class="card">
<div class="card-header p-0" id="headingTwo">
<h2 class="mb-0">
<button class="btn btn-light btn-block text-left collapsed p-3 rounded-0" type="button" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
Collapsible Group Item #2
</button>
</h2>
</div>
<div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionExample">
<div class="card-body">
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.
</div>
</div>
</div>
<div class="card">
<div class="card-header p-0" id="headingThree">
<h2 class="mb-0">
<button class="btn btn-light btn-block text-left collapsed p-3 rounded-0" type="button" data-toggle="collapse" data-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
Collapsible Group Item #3
</button>
</h2>
</div>
<div id="collapseThree" class="collapse" aria-labelledby="headingThree" data-parent="#accordionExample">
<div class="card-body">
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.
</div>
</div>
</div>
</div>
{{< /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 `<a>` or `<div>`), the attribute `role="button"` should be added to the element.

View file

@ -10,8 +10,6 @@ toc: true
Wrap a pair of `<input class="form-control">` and `<label>` elements in `.form-floating` to enable floating labels with Bootstrap's textual form fields. A `placeholder` is required on each `<input>` as our method of CSS-only floating labels uses the `:placeholder-shown` pseudo-element. Also note that the `<input>` must come first so we can utilize a sibling selector (e.g., `~`).
This approach works in the new Microsoft Edge built on Chromium and gracefully degrades on older versions.
{{< example >}}
<div class="form-floating mb-3">
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">

View file

@ -34,9 +34,9 @@ Place one add-on or button on either side of an input. You may also place one on
</div>
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Username">
<input type="text" class="form-control" placeholder="Username" aria-label="Username">
<span class="input-group-text">@</span>
<input type="text" class="form-control" placeholder="Server">
<input type="text" class="form-control" placeholder="Server" aria-label="Server">
</div>
<div class="input-group">
@ -289,22 +289,22 @@ Input groups include support for custom selects and custom file inputs. Browser
{{< example >}}
<div class="input-group mb-3">
<span class="input-group-text" id="inputGroupFileAddon01">Upload</span>
<input type="file" class="form-control" id="inputGroupFile01" aria-describedby="inputGroupFileAddon01">
<label class="input-group-text" for="inputGroupFile01">Upload</label>
<input type="file" class="form-control" id="inputGroupFile01">
</div>
<div class="input-group mb-3">
<input type="file" class="form-control" id="inputGroupFile02" aria-describedby="inputGroupFileAddon02">
<span class="input-group-text" id="inputGroupFileAddon02">Upload</span>
<input type="file" class="form-control" id="inputGroupFile02">
<label class="input-group-text" for="inputGroupFile02">Upload</label>
</div>
<div class="input-group mb-3">
<button class="btn btn-outline-secondary" type="button" id="inputGroupFileAddon03">Button</button>
<input type="file" class="form-control" id="inputGroupFile03" aria-describedby="inputGroupFileAddon03">
<input type="file" class="form-control" id="inputGroupFile03" aria-describedby="inputGroupFileAddon03" aria-label="Upload">
</div>
<div class="input-group">
<input type="file" class="form-control" id="inputGroupFile04" aria-describedby="inputGroupFileAddon04">
<input type="file" class="form-control" id="inputGroupFile04" aria-describedby="inputGroupFileAddon04" aria-label="Upload">
<button class="btn btn-outline-secondary" type="button" id="inputGroupFileAddon04">Button</button>
</div>
{{< /example >}}

View file

@ -8,7 +8,7 @@ toc: true
## Supported browsers
Bootstrap supports the **latest, stable releases** of all major browsers and platforms. This also includes the latest version of Legacy Edge (EdgeHTML layout engine).
Bootstrap supports the **latest, stable releases** of all major browsers and platforms.
Alternative browsers which use the latest version of WebKit, Blink, or Gecko, whether directly or via the platform's web view API, are not explicitly supported. However, Bootstrap should (in most cases) display and function correctly in these browsers as well. More specific support information is provided below.

View file

@ -15,3 +15,7 @@ You can use the `.link-*` classes to colorize links. Unlike the [`.text-*` class
{{- end -}}
{{< /colored-links.inline >}}
{{< /example >}}
{{< callout info >}}
Some of the link styles use a relatively light foreground color, and should only be used on a dark background in order to have sufficient contrast.
{{< /callout >}}

View file

@ -9,6 +9,10 @@ toc: true
## v5.0.0-alpha3
### Browser support
- Dropped support for Microsoft Edge Legacy. See [here](#browser-support-1) for the previous browser support changes.
### Colors
- The color system which worked with `color-level()` and `$theme-color-interval` was removed in favor of a new color system.

View file

@ -7,21 +7,24 @@ aliases: "/docs/5.0/utilities/"
toc: true
---
The bootstrap utilities are generated with the utility API which can be used to change or extend Bootstrap's utility classes. If you don't have any idea what Sass maps are, you can consult the [official docs](https://sass-lang.com/documentation/values/maps) to get started.
Bootstrap utilities are generated with our utility API and can be used to modify or extend our default set of utility classes via Sass. Our utility API is based on a series of Sass maps and functions for generating families of classes with various options. If you're unfamiliar with Sass maps, read up on the [official Sass docs](https://sass-lang.com/documentation/values/maps) to get started.
The `$utilities` map contains all utilities and is later merged with your custom `$utilities` map if present. The utility map contains a keyed list of utility groups which accept the following options:
The `$utilities` map contains all our utilities and is later merged with your custom `$utilities` map, if present. The utility map contains a keyed list of utility groups which accept the following options:
- `property`: Name of the property, this can be a string or an array of strings (needed for eg. horizontal paddings or margins).
- `responsive` _(optional)_: Boolean indicating if responsive classes need to be generated. `false` by default.
- `rfs` _(optional)_: Variable to enable fluid rescaling. Have a look at the [RFS]({{< docsref "/getting-started/rfs" >}}) page to find out how this works. `false` by default.
- `class` _(optional)_: Variable to change the class name if you don't want it to be the same as the property. In case you don't provide the `class` key and `property` key is an array of strings, the class name will be the first element of the `property` array.
- `values`: This can be a list of values or a map if you don't want the class name to be the same as the value. If null is used as map key, it isn't rendered.
- `print` _(optional)_: Boolean indicating if print classes need to be generated. `false` by default.
{{< bs-table "table text-left" >}}
| Option | Type | Description |
| --- | --- | --- |
| `property` | **Required** | Name of the property, this can be a string or an array of strings (e.g., horizontal paddings or margins). |
| `values` | **Required** | List of values, or a map if you don't want the class name to be the same as the value. If `null` is used as map key, it isn't compiled. |
| `class` | Optional | Variable for the class name if you don't want it to be the same as the property. In case you don't provide the `class` key and `property` key is an array of strings, the class name will be the first element of the `property` array. |
| `responsive` | Optional | Boolean indicating if responsive classes need to be generated. `false` by default. |
| `rfs` | Optional | Boolean to enable fluid rescaling. Have a look at the [RFS]({{< docsref "/getting-started/rfs" >}}) page to find out how this works. `false` by default. |
| `print` | Optional | Boolean indicating if print classes need to be generated. `false` by default. |
{{< /bs-table >}}
## API explained
## Adding utilities to the utility API
All utility variables are added to the `$utilities` variable. Custom utility groups can added like this:
All utility variables are added to the `$utilities` variable within our `_utilities.scss` stylesheet. Each group of utilities looks something like this:
```scss
$utilities: (
@ -38,30 +41,19 @@ $utilities: (
);
```
Output:
Which outputs the following:
```css
.opacity-0 {
opacity: 0;
}
.opacity-25 {
opacity: .25;
}
.opacity-50 {
opacity: .5;
}
.opacity-75 {
opacity: .75;
}
.opacity-100 {
opacity: 1;
}
.opacity-0 { opacity: 0; }
.opacity-25 { opacity: .25; }
.opacity-50 { opacity: .5; }
.opacity-75 { opacity: .75; }
.opacity-100 { opacity: 1; }
```
### Custom class prefix
## Changing the class prefix
With the `class` option, the class prefix can be changed:
Use the `class` option to change the class prefix used in the compiled CSS:
```scss
$utilities: (
@ -82,26 +74,16 @@ $utilities: (
Output:
```css
.o-0 {
opacity: 0;
}
.o-25 {
opacity: .25;
}
.o-50 {
opacity: .5;
}
.o-75 {
opacity: .75;
}
.o-100 {
opacity: 1;
}
.o-0 { opacity: 0; }
.o-25 { opacity: .25; }
.o-50 { opacity: .5; }
.o-75 { opacity: .75; }
.o-100 { opacity: 1; }
```
## Responsive utilities
### Responsive utilities
With the `responsive` option, responsive utility classes can be generated:
Add the `responsive` boolean to generate responsive utilities (e.g., `.opacity-md-25`) across [all breakpoints]({{< docsref "/layout/breakpoints" >}}).
```scss
$utilities: (
@ -122,95 +104,56 @@ $utilities: (
Output:
```css
.opacity-0 {
opacity: 0;
}
.opacity-25 {
opacity: .25;
}
.opacity-50 {
opacity: .5;
}
.opacity-75 {
opacity: .75;
}
.opacity-100 {
opacity: 1;
}
.opacity-0 { opacity: 0; }
.opacity-25 { opacity: .25; }
.opacity-50 { opacity: .5; }
.opacity-75 { opacity: .75; }
.opacity-100 { opacity: 1; }
@media (min-width: 576px) {
.opacity-sm-0 {
opacity: 0;
}
.opacity-sm-25 {
opacity: .25;
}
.opacity-sm-50 {
opacity: .5;
}
.opacity-sm-75 {
opacity: .75;
}
.opacity-sm-100 {
opacity: 1;
}
.opacity-sm-0 { opacity: 0; }
.opacity-sm-25 { opacity: .25; }
.opacity-sm-50 { opacity: .5; }
.opacity-sm-75 { opacity: .75; }
.opacity-sm-100 { opacity: 1; }
}
@media (min-width: 768px) {
.opacity-md-0 {
opacity: 0;
}
.opacity-md-25 {
opacity: .25;
}
.opacity-md-50 {
opacity: .5;
}
.opacity-md-75 {
opacity: .75;
}
.opacity-md-100 {
opacity: 1;
}
.opacity-md-0 { opacity: 0; }
.opacity-md-25 { opacity: .25; }
.opacity-md-50 { opacity: .5; }
.opacity-md-75 { opacity: .75; }
.opacity-md-100 { opacity: 1; }
}
@media (min-width: 992px) {
.opacity-lg-0 {
opacity: 0;
}
.opacity-lg-25 {
opacity: .25;
}
.opacity-lg-50 {
opacity: .5;
}
.opacity-lg-75 {
opacity: .75;
}
.opacity-lg-100 {
opacity: 1;
}
.opacity-lg-0 { opacity: 0; }
.opacity-lg-25 { opacity: .25; }
.opacity-lg-50 { opacity: .5; }
.opacity-lg-75 { opacity: .75; }
.opacity-lg-100 { opacity: 1; }
}
@media (min-width: 1200px) {
.opacity-xl-0 {
opacity: 0;
}
.opacity-xl-25 {
opacity: .25;
}
.opacity-xl-50 {
opacity: .5;
}
.opacity-xl-75 {
opacity: .75;
}
.opacity-xl-100 {
opacity: 1;
}
.opacity-xl-0 { opacity: 0; }
.opacity-xl-25 { opacity: .25; }
.opacity-xl-50 { opacity: .5; }
.opacity-xl-75 { opacity: .75; }
.opacity-xl-100 { opacity: 1; }
}
@media (min-width: 1400px) {
.opacity-xxl-0 { opacity: 0; }
.opacity-xxl-25 { opacity: .25; }
.opacity-xxl-50 { opacity: .5; }
.opacity-xxl-75 { opacity: .75; }
.opacity-xxl-100 { opacity: 1; }
}
```
## Changing utilities
### Changing utilities
Overriding excising utilities is possible by using the same key. For example if you want more responsive overflow
utility classes you can do this:
Override existing utilities by using the same key. For example, if you want additional responsive overflow utility classes, you can do this:
```scss
$utilities: (
@ -222,16 +165,14 @@ $utilities: (
);
```
### Print utilities
## Print utilities
Enabling the `print` option will **also** generate utility classes for print.
Enabling the `print` option will **also** generate utility classes for print, which are only applied within the `@media print { ... }` media query.
```scss
$utilities: (
"opacity": (
property: opacity,
class: o,
print: true,
values: (
0: 0,
@ -247,47 +188,79 @@ $utilities: (
Output:
```css
.o-0 {
opacity: 0;
}
.o-25 {
opacity: .25;
}
.o-50 {
opacity: .5;
}
.o-75 {
opacity: .75;
}
.o-100 {
opacity: 1;
}
.opacity-0 { opacity: 0; }
.opacity-25 { opacity: .25; }
.opacity-50 { opacity: .5; }
.opacity-75 { opacity: .75; }
.opacity-100 { opacity: 1; }
@media print {
.o-print-0 {
opacity: 0;
}
.o-print-25 {
opacity: .25;
}
.o-print-50 {
opacity: .5;
}
.o-print-75 {
opacity: .75;
}
.o-print-100 {
opacity: 1;
}
.opacity-print-0 { opacity: 0; }
.opacity-print-25 { opacity: .25; }
.opacity-print-50 { opacity: .5; }
.opacity-print-75 { opacity: .75; }
.opacity-print-100 { opacity: 1; }
}
```
## Removing utilities
## Using the API
Utilities can also be removed by changing the group key to `null`:
Now that you're familiar with how the utilities API works, learn how to add your own custom classes and modify our default utilities.
### Add utilities
New utilities can be added to the default `$utilities` map with a `map-merge`. Make sure our `_utilities.scss` is imported first, then use the `map-merge` to add your additional utilities. For example, here's how to add a responsive `cursor` utility with three values.
```scss
$utilities: (
"float": null,
@import "bootstrap/scss/utilities";
$utilities: map-merge(
$utilities,
(
"cursor": (
property: cursor,
class: cursor
responsive: true,
values: auto pointer grab,
)
)
);
```
### Modify utilities
Modify existing utilities in the default `$utilities` map with `map-get` and `map-merge` functions. In the example below, we're adding an additional value to the `width` utilities. Start with an initial `map-merge` and then specify which utility you want to modify. From there, fetch the nested `"width"` map with `map-get` to access and modify the utility's options and values.
```scss
@import "bootstrap/scss/utilities";
$utilities: map-merge(
$utilities,
(
"width": map-merge(
map-get($utilities, "width"),
(
values: map-merge(
map-get(map-get($utilities, "width"), "values"),
(10: 10%),
),
),
),
)
);
```
### Remove utilities
Remove any of the default utilities by setting the group key to `null`. For example, to remove all our `width` utilities, create a `$utilities` `map-merge` and add `"width": null` within.
```scss
@import "bootstrap/scss/utilities";
$utilities: map-merge(
$utilities,
(
"width": null
)
);
```

View file

@ -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`

View file

@ -53,6 +53,7 @@
- title: Components
pages:
- title: Accordion
- title: Alerts
- title: Badge
- title: Breadcrumb

View file

@ -23,7 +23,6 @@
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}