vanilla 19.0

This commit is contained in:
Ernad Husremovic 2025-10-08 10:49:46 +02:00
parent 991d2234ca
commit d1963a3c3a
3066 changed files with 1651266 additions and 922560 deletions

View file

@ -1,7 +1,6 @@
The MIT License (MIT)
Copyright (c) 2011-2021 Twitter, Inc.
Copyright (c) 2011-2021 The Bootstrap Authors
Copyright (c) 2011-2024 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,155 +1,24 @@
/*!
* Bootstrap alert.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap alert.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/event-handler.js'), require('./base-component.js')) :
typeof define === 'function' && define.amd ? define(['./dom/event-handler', './base-component'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Alert = factory(global.EventHandler, global.Base));
})(this, (function (EventHandler, BaseComponent) { 'use strict';
const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./util/component-functions.js'), require('./util/index.js')) :
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './util/component-functions', './util/index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Alert = factory(global.BaseComponent, global.EventHandler, global.ComponentFunctions, global.Index));
})(this, (function (BaseComponent, EventHandler, componentFunctions_js, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Bootstrap alert.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const getSelector = element => {
let selector = element.getAttribute('data-bs-target');
if (!selector || selector === '#') {
let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
// so everything starting with `#` or `.`. If a "real" URL is used as the selector,
// `document.querySelector` will rightfully complain it is invalid.
// See https://github.com/twbs/bootstrap/issues/32273
if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
return null;
} // Just in case some CMS puts out a full URL with the anchor appended
if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
hrefAttr = `#${hrefAttr.split('#')[1]}`;
}
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
}
return selector;
};
const getElementFromSelector = element => {
const selector = getSelector(element);
return selector ? document.querySelector(selector) : null;
};
const isDisabled = element => {
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
return true;
}
if (element.classList.contains('disabled')) {
return true;
}
if (typeof element.disabled !== 'undefined') {
return element.disabled;
}
return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
};
const getjQuery = () => {
const {
jQuery
} = window;
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
return jQuery;
}
return null;
};
const DOMContentLoadedCallbacks = [];
const onDOMContentLoaded = callback => {
if (document.readyState === 'loading') {
// add listener on the first call when the document is in loading state
if (!DOMContentLoadedCallbacks.length) {
document.addEventListener('DOMContentLoaded', () => {
DOMContentLoadedCallbacks.forEach(callback => callback());
});
}
DOMContentLoadedCallbacks.push(callback);
} else {
callback();
}
};
const defineJQueryPlugin = plugin => {
onDOMContentLoaded(() => {
const $ = getjQuery();
/* istanbul ignore if */
if ($) {
const name = plugin.NAME;
const JQUERY_NO_CONFLICT = $.fn[name];
$.fn[name] = plugin.jQueryInterface;
$.fn[name].Constructor = plugin;
$.fn[name].noConflict = () => {
$.fn[name] = JQUERY_NO_CONFLICT;
return plugin.jQueryInterface;
};
}
});
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/component-functions.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const enableDismissTrigger = (component, method = 'hide') => {
const clickEvent = `click.dismiss${component.EVENT_KEY}`;
const name = component.NAME;
EventHandler__default.default.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault();
}
if (isDisabled(this)) {
return;
}
const target = getElementFromSelector(this) || this.closest(`.${name}`);
const instance = component.getOrCreateInstance(target); // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
instance[method]();
});
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): alert.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'alert';
@ -159,75 +28,61 @@
const EVENT_CLOSED = `closed${EVENT_KEY}`;
const CLASS_NAME_FADE = 'fade';
const CLASS_NAME_SHOW = 'show';
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
* Class definition
*/
class Alert extends BaseComponent__default.default {
class Alert extends BaseComponent {
// Getters
static get NAME() {
return NAME;
} // Public
}
// Public
close() {
const closeEvent = EventHandler__default.default.trigger(this._element, EVENT_CLOSE);
const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE);
if (closeEvent.defaultPrevented) {
return;
}
this._element.classList.remove(CLASS_NAME_SHOW);
const isAnimated = this._element.classList.contains(CLASS_NAME_FADE);
this._queueCallback(() => this._destroyElement(), this._element, isAnimated);
} // Private
}
// Private
_destroyElement() {
this._element.remove();
EventHandler__default.default.trigger(this._element, EVENT_CLOSED);
EventHandler.trigger(this._element, EVENT_CLOSED);
this.dispose();
} // Static
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Alert.getOrCreateInstance(this);
if (typeof config !== 'string') {
return;
}
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`);
}
data[config](this);
});
}
}
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
* Data API implementation
*/
componentFunctions_js.enableDismissTrigger(Alert, 'close');
enableDismissTrigger(Alert, 'close');
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .Alert to jQuery only if jQuery is present
*/
defineJQueryPlugin(Alert);
index_js.defineJQueryPlugin(Alert);
return Alert;

View file

@ -1,180 +1,81 @@
/*!
* Bootstrap base-component.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap base-component.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/data.js'), require('./dom/event-handler.js')) :
typeof define === 'function' && define.amd ? define(['./dom/data', './dom/event-handler'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Base = factory(global.Data, global.EventHandler));
})(this, (function (Data, EventHandler) { 'use strict';
const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
const Data__default = /*#__PURE__*/_interopDefaultLegacy(Data);
const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/data.js'), require('./dom/event-handler.js'), require('./util/config.js'), require('./util/index.js')) :
typeof define === 'function' && define.amd ? define(['./dom/data', './dom/event-handler', './util/config', './util/index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.BaseComponent = factory(global.Data, global.EventHandler, global.Config, global.Index));
})(this, (function (Data, EventHandler, Config, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Bootstrap base-component.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const MILLISECONDS_MULTIPLIER = 1000;
const TRANSITION_END = 'transitionend'; // Shoutout AngusCroll (https://goo.gl/pxwQGp)
const getTransitionDurationFromElement = element => {
if (!element) {
return 0;
} // Get transition-duration of the element
let {
transitionDuration,
transitionDelay
} = window.getComputedStyle(element);
const floatTransitionDuration = Number.parseFloat(transitionDuration);
const floatTransitionDelay = Number.parseFloat(transitionDelay); // Return 0 if element or transition duration is not found
if (!floatTransitionDuration && !floatTransitionDelay) {
return 0;
} // If multiple durations are defined, take the first
transitionDuration = transitionDuration.split(',')[0];
transitionDelay = transitionDelay.split(',')[0];
return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;
};
const triggerTransitionEnd = element => {
element.dispatchEvent(new Event(TRANSITION_END));
};
const isElement = obj => {
if (!obj || typeof obj !== 'object') {
return false;
}
if (typeof obj.jquery !== 'undefined') {
obj = obj[0];
}
return typeof obj.nodeType !== 'undefined';
};
const getElement = obj => {
if (isElement(obj)) {
// it's a jQuery object or a node element
return obj.jquery ? obj[0] : obj;
}
if (typeof obj === 'string' && obj.length > 0) {
return document.querySelector(obj);
}
return null;
};
const execute = callback => {
if (typeof callback === 'function') {
callback();
}
};
const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
if (!waitForTransition) {
execute(callback);
return;
}
const durationPadding = 5;
const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;
let called = false;
const handler = ({
target
}) => {
if (target !== transitionElement) {
return;
}
called = true;
transitionElement.removeEventListener(TRANSITION_END, handler);
execute(callback);
};
transitionElement.addEventListener(TRANSITION_END, handler);
setTimeout(() => {
if (!called) {
triggerTransitionEnd(transitionElement);
}
}, emulatedDuration);
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): base-component.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const VERSION = '5.1.3';
const VERSION = '5.3.3';
class BaseComponent {
constructor(element) {
element = getElement(element);
/**
* Class definition
*/
class BaseComponent extends Config {
constructor(element, config) {
super();
element = index_js.getElement(element);
if (!element) {
return;
}
this._element = element;
Data__default.default.set(this._element, this.constructor.DATA_KEY, this);
this._config = this._getConfig(config);
Data.set(this._element, this.constructor.DATA_KEY, this);
}
// Public
dispose() {
Data__default.default.remove(this._element, this.constructor.DATA_KEY);
EventHandler__default.default.off(this._element, this.constructor.EVENT_KEY);
Object.getOwnPropertyNames(this).forEach(propertyName => {
Data.remove(this._element, this.constructor.DATA_KEY);
EventHandler.off(this._element, this.constructor.EVENT_KEY);
for (const propertyName of Object.getOwnPropertyNames(this)) {
this[propertyName] = null;
});
}
}
_queueCallback(callback, element, isAnimated = true) {
executeAfterTransition(callback, element, isAnimated);
index_js.executeAfterTransition(callback, element, isAnimated);
}
_getConfig(config) {
config = this._mergeConfigObj(config, this._element);
config = this._configAfterMerge(config);
this._typeCheckConfig(config);
return config;
}
/** Static */
// Static
static getInstance(element) {
return Data__default.default.get(getElement(element), this.DATA_KEY);
return Data.get(index_js.getElement(element), this.DATA_KEY);
}
static getOrCreateInstance(element, config = {}) {
return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null);
}
static get VERSION() {
return VERSION;
}
static get NAME() {
throw new Error('You have to implement the static method "NAME", for each component!');
}
static get DATA_KEY() {
return `bs.${this.NAME}`;
}
static get EVENT_KEY() {
return `.${this.DATA_KEY}`;
}
static eventName(name) {
return `${name}${this.EVENT_KEY}`;
}
}
return BaseComponent;

View file

@ -1,84 +1,24 @@
/*!
* Bootstrap button.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap button.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/event-handler.js'), require('./base-component.js')) :
typeof define === 'function' && define.amd ? define(['./dom/event-handler', './base-component'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Button = factory(global.EventHandler, global.Base));
})(this, (function (EventHandler, BaseComponent) { 'use strict';
const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./util/index.js')) :
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './util/index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Button = factory(global.BaseComponent, global.EventHandler, global.Index));
})(this, (function (BaseComponent, EventHandler, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Bootstrap button.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const getjQuery = () => {
const {
jQuery
} = window;
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
return jQuery;
}
return null;
};
const DOMContentLoadedCallbacks = [];
const onDOMContentLoaded = callback => {
if (document.readyState === 'loading') {
// add listener on the first call when the document is in loading state
if (!DOMContentLoadedCallbacks.length) {
document.addEventListener('DOMContentLoaded', () => {
DOMContentLoadedCallbacks.forEach(callback => callback());
});
}
DOMContentLoadedCallbacks.push(callback);
} else {
callback();
}
};
const defineJQueryPlugin = plugin => {
onDOMContentLoaded(() => {
const $ = getjQuery();
/* istanbul ignore if */
if ($) {
const name = plugin.NAME;
const JQUERY_NO_CONFLICT = $.fn[name];
$.fn[name] = plugin.jQueryInterface;
$.fn[name].Constructor = plugin;
$.fn[name].noConflict = () => {
$.fn[name] = JQUERY_NO_CONFLICT;
return plugin.jQueryInterface;
};
}
});
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): button.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'button';
@ -88,57 +28,50 @@
const CLASS_NAME_ACTIVE = 'active';
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="button"]';
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
* Class definition
*/
class Button extends BaseComponent__default.default {
class Button extends BaseComponent {
// Getters
static get NAME() {
return NAME;
} // Public
}
// Public
toggle() {
// Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method
this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE));
} // Static
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Button.getOrCreateInstance(this);
if (config === 'toggle') {
data[config]();
}
});
}
}
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
* Data API implementation
*/
EventHandler__default.default.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {
event.preventDefault();
const button = event.target.closest(SELECTOR_DATA_TOGGLE);
const data = Button.getOrCreateInstance(button);
data.toggle();
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .Button to jQuery only if jQuery is present
*/
defineJQueryPlugin(Button);
index_js.defineJQueryPlugin(Button);
return Button;

View file

@ -1,203 +1,24 @@
/*!
* Bootstrap carousel.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap carousel.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./base-component.js')) :
typeof define === 'function' && define.amd ? define(['./dom/event-handler', './dom/manipulator', './dom/selector-engine', './base-component'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Carousel = factory(global.EventHandler, global.Manipulator, global.SelectorEngine, global.Base));
})(this, (function (EventHandler, Manipulator, SelectorEngine, BaseComponent) { 'use strict';
const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
const Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
const SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./util/index.js'), require('./util/swipe.js')) :
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './dom/manipulator', './dom/selector-engine', './util/index', './util/swipe'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Carousel = factory(global.BaseComponent, global.EventHandler, global.Manipulator, global.SelectorEngine, global.Index, global.Swipe));
})(this, (function (BaseComponent, EventHandler, Manipulator, SelectorEngine, index_js, Swipe) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Bootstrap carousel.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const TRANSITION_END = 'transitionend'; // Shoutout AngusCroll (https://goo.gl/pxwQGp)
const toType = obj => {
if (obj === null || obj === undefined) {
return `${obj}`;
}
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
};
const getSelector = element => {
let selector = element.getAttribute('data-bs-target');
if (!selector || selector === '#') {
let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
// so everything starting with `#` or `.`. If a "real" URL is used as the selector,
// `document.querySelector` will rightfully complain it is invalid.
// See https://github.com/twbs/bootstrap/issues/32273
if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
return null;
} // Just in case some CMS puts out a full URL with the anchor appended
if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
hrefAttr = `#${hrefAttr.split('#')[1]}`;
}
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
}
return selector;
};
const getElementFromSelector = element => {
const selector = getSelector(element);
return selector ? document.querySelector(selector) : null;
};
const triggerTransitionEnd = element => {
element.dispatchEvent(new Event(TRANSITION_END));
};
const isElement = obj => {
if (!obj || typeof obj !== 'object') {
return false;
}
if (typeof obj.jquery !== 'undefined') {
obj = obj[0];
}
return typeof obj.nodeType !== 'undefined';
};
const typeCheckConfig = (componentName, config, configTypes) => {
Object.keys(configTypes).forEach(property => {
const expectedTypes = configTypes[property];
const value = config[property];
const valueType = value && isElement(value) ? 'element' : toType(value);
if (!new RegExp(expectedTypes).test(valueType)) {
throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
}
});
};
const isVisible = element => {
if (!isElement(element) || element.getClientRects().length === 0) {
return false;
}
return getComputedStyle(element).getPropertyValue('visibility') === 'visible';
};
/**
* Trick to restart an element's animation
*
* @param {HTMLElement} element
* @return void
*
* @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
*/
const reflow = element => {
// eslint-disable-next-line no-unused-expressions
element.offsetHeight;
};
const getjQuery = () => {
const {
jQuery
} = window;
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
return jQuery;
}
return null;
};
const DOMContentLoadedCallbacks = [];
const onDOMContentLoaded = callback => {
if (document.readyState === 'loading') {
// add listener on the first call when the document is in loading state
if (!DOMContentLoadedCallbacks.length) {
document.addEventListener('DOMContentLoaded', () => {
DOMContentLoadedCallbacks.forEach(callback => callback());
});
}
DOMContentLoadedCallbacks.push(callback);
} else {
callback();
}
};
const isRTL = () => document.documentElement.dir === 'rtl';
const defineJQueryPlugin = plugin => {
onDOMContentLoaded(() => {
const $ = getjQuery();
/* istanbul ignore if */
if ($) {
const name = plugin.NAME;
const JQUERY_NO_CONFLICT = $.fn[name];
$.fn[name] = plugin.jQueryInterface;
$.fn[name].Constructor = plugin;
$.fn[name].noConflict = () => {
$.fn[name] = JQUERY_NO_CONFLICT;
return plugin.jQueryInterface;
};
}
});
};
/**
* Return the previous/next element of a list.
*
* @param {array} list The list of elements
* @param activeElement The active element
* @param shouldGetNext Choose to get next or previous element
* @param isCycleAllowed
* @return {Element|elem} The proper element
*/
const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
let index = list.indexOf(activeElement); // if the element does not exist in the list return an element depending on the direction and if cycle is allowed
if (index === -1) {
return list[!shouldGetNext && isCycleAllowed ? list.length - 1 : 0];
}
const listLength = list.length;
index += shouldGetNext ? 1 : -1;
if (isCycleAllowed) {
index = (index + listLength) % listLength;
}
return list[Math.max(0, Math.min(index, listLength - 1))];
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): carousel.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'carousel';
@ -208,41 +29,15 @@
const ARROW_RIGHT_KEY = 'ArrowRight';
const TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch
const SWIPE_THRESHOLD = 40;
const Default = {
interval: 5000,
keyboard: true,
slide: false,
pause: 'hover',
wrap: true,
touch: true
};
const DefaultType = {
interval: '(number|boolean)',
keyboard: 'boolean',
slide: '(boolean|string)',
pause: '(string|boolean)',
wrap: 'boolean',
touch: 'boolean'
};
const ORDER_NEXT = 'next';
const ORDER_PREV = 'prev';
const DIRECTION_LEFT = 'left';
const DIRECTION_RIGHT = 'right';
const KEY_TO_DIRECTION = {
[ARROW_LEFT_KEY]: DIRECTION_RIGHT,
[ARROW_RIGHT_KEY]: DIRECTION_LEFT
};
const EVENT_SLIDE = `slide${EVENT_KEY}`;
const EVENT_SLID = `slid${EVENT_KEY}`;
const EVENT_KEYDOWN = `keydown${EVENT_KEY}`;
const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`;
const EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`;
const EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`;
const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`;
const EVENT_TOUCHEND = `touchend${EVENT_KEY}`;
const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`;
const EVENT_POINTERUP = `pointerup${EVENT_KEY}`;
const EVENT_DRAG_START = `dragstart${EVENT_KEY}`;
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`;
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
@ -253,489 +48,339 @@
const CLASS_NAME_START = 'carousel-item-start';
const CLASS_NAME_NEXT = 'carousel-item-next';
const CLASS_NAME_PREV = 'carousel-item-prev';
const CLASS_NAME_POINTER_EVENT = 'pointer-event';
const SELECTOR_ACTIVE = '.active';
const SELECTOR_ACTIVE_ITEM = '.active.carousel-item';
const SELECTOR_ITEM = '.carousel-item';
const SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM;
const SELECTOR_ITEM_IMG = '.carousel-item img';
const SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev';
const SELECTOR_INDICATORS = '.carousel-indicators';
const SELECTOR_INDICATOR = '[data-bs-target]';
const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]';
const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]';
const POINTER_TYPE_TOUCH = 'touch';
const POINTER_TYPE_PEN = 'pen';
const KEY_TO_DIRECTION = {
[ARROW_LEFT_KEY]: DIRECTION_RIGHT,
[ARROW_RIGHT_KEY]: DIRECTION_LEFT
};
const Default = {
interval: 5000,
keyboard: true,
pause: 'hover',
ride: false,
touch: true,
wrap: true
};
const DefaultType = {
interval: '(number|boolean)',
// TODO:v6 remove boolean support
keyboard: 'boolean',
pause: '(string|boolean)',
ride: '(boolean|string)',
touch: 'boolean',
wrap: 'boolean'
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
* Class definition
*/
class Carousel extends BaseComponent__default.default {
class Carousel extends BaseComponent {
constructor(element, config) {
super(element);
this._items = null;
super(element, config);
this._interval = null;
this._activeElement = null;
this._isPaused = false;
this._isSliding = false;
this.touchTimeout = null;
this.touchStartX = 0;
this.touchDeltaX = 0;
this._config = this._getConfig(config);
this._indicatorsElement = SelectorEngine__default.default.findOne(SELECTOR_INDICATORS, this._element);
this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;
this._pointerEvent = Boolean(window.PointerEvent);
this._swipeHelper = null;
this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element);
this._addEventListeners();
} // Getters
if (this._config.ride === CLASS_NAME_CAROUSEL) {
this.cycle();
}
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
} // Public
}
// Public
next() {
this._slide(ORDER_NEXT);
}
nextWhenVisible() {
// FIXME TODO use `document.visibilityState`
// Don't call next when the page isn't visible
// or the carousel or its parent isn't visible
if (!document.hidden && isVisible(this._element)) {
if (!document.hidden && index_js.isVisible(this._element)) {
this.next();
}
}
prev() {
this._slide(ORDER_PREV);
}
pause(event) {
if (!event) {
this._isPaused = true;
}
if (SelectorEngine__default.default.findOne(SELECTOR_NEXT_PREV, this._element)) {
triggerTransitionEnd(this._element);
this.cycle(true);
}
clearInterval(this._interval);
this._interval = null;
}
cycle(event) {
if (!event) {
this._isPaused = false;
}
if (this._interval) {
clearInterval(this._interval);
this._interval = null;
}
if (this._config && this._config.interval && !this._isPaused) {
this._updateInterval();
this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);
}
}
to(index) {
this._activeElement = SelectorEngine__default.default.findOne(SELECTOR_ACTIVE_ITEM, this._element);
const activeIndex = this._getItemIndex(this._activeElement);
if (index > this._items.length - 1 || index < 0) {
return;
}
pause() {
if (this._isSliding) {
EventHandler__default.default.one(this._element, EVENT_SLID, () => this.to(index));
index_js.triggerTransitionEnd(this._element);
}
this._clearInterval();
}
cycle() {
this._clearInterval();
this._updateInterval();
this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval);
}
_maybeEnableCycle() {
if (!this._config.ride) {
return;
}
if (this._isSliding) {
EventHandler.one(this._element, EVENT_SLID, () => this.cycle());
return;
}
this.cycle();
}
to(index) {
const items = this._getItems();
if (index > items.length - 1 || index < 0) {
return;
}
if (this._isSliding) {
EventHandler.one(this._element, EVENT_SLID, () => this.to(index));
return;
}
const activeIndex = this._getItemIndex(this._getActive());
if (activeIndex === index) {
this.pause();
this.cycle();
return;
}
const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV;
this._slide(order, items[index]);
}
dispose() {
if (this._swipeHelper) {
this._swipeHelper.dispose();
}
super.dispose();
}
this._slide(order, this._items[index]);
} // Private
_getConfig(config) {
config = { ...Default,
...Manipulator__default.default.getDataAttributes(this._element),
...(typeof config === 'object' ? config : {})
};
typeCheckConfig(NAME, config, DefaultType);
// Private
_configAfterMerge(config) {
config.defaultInterval = config.interval;
return config;
}
_handleSwipe() {
const absDeltax = Math.abs(this.touchDeltaX);
if (absDeltax <= SWIPE_THRESHOLD) {
return;
}
const direction = absDeltax / this.touchDeltaX;
this.touchDeltaX = 0;
if (!direction) {
return;
}
this._slide(direction > 0 ? DIRECTION_RIGHT : DIRECTION_LEFT);
}
_addEventListeners() {
if (this._config.keyboard) {
EventHandler__default.default.on(this._element, EVENT_KEYDOWN, event => this._keydown(event));
EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event));
}
if (this._config.pause === 'hover') {
EventHandler__default.default.on(this._element, EVENT_MOUSEENTER, event => this.pause(event));
EventHandler__default.default.on(this._element, EVENT_MOUSELEAVE, event => this.cycle(event));
EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause());
EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle());
}
if (this._config.touch && this._touchSupported) {
if (this._config.touch && Swipe.isSupported()) {
this._addTouchEventListeners();
}
}
_addTouchEventListeners() {
const hasPointerPenTouch = event => {
return this._pointerEvent && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH);
};
const start = event => {
if (hasPointerPenTouch(event)) {
this.touchStartX = event.clientX;
} else if (!this._pointerEvent) {
this.touchStartX = event.touches[0].clientX;
}
};
const move = event => {
// ensure swiping with one touch and not pinching
this.touchDeltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this.touchStartX;
};
const end = event => {
if (hasPointerPenTouch(event)) {
this.touchDeltaX = event.clientX - this.touchStartX;
}
this._handleSwipe();
if (this._config.pause === 'hover') {
// If it's a touch-enabled device, mouseenter/leave are fired as
// part of the mouse compatibility events on first tap - the carousel
// would stop cycling until user tapped out of it;
// here, we listen for touchend, explicitly pause the carousel
// (as if it's the second time we tap on it, mouseenter compat event
// is NOT fired) and after a timeout (to allow for mouse compatibility
// events to fire) we explicitly restart cycling
this.pause();
if (this.touchTimeout) {
clearTimeout(this.touchTimeout);
}
this.touchTimeout = setTimeout(event => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval);
}
};
SelectorEngine__default.default.find(SELECTOR_ITEM_IMG, this._element).forEach(itemImg => {
EventHandler__default.default.on(itemImg, EVENT_DRAG_START, event => event.preventDefault());
});
if (this._pointerEvent) {
EventHandler__default.default.on(this._element, EVENT_POINTERDOWN, event => start(event));
EventHandler__default.default.on(this._element, EVENT_POINTERUP, event => end(event));
this._element.classList.add(CLASS_NAME_POINTER_EVENT);
} else {
EventHandler__default.default.on(this._element, EVENT_TOUCHSTART, event => start(event));
EventHandler__default.default.on(this._element, EVENT_TOUCHMOVE, event => move(event));
EventHandler__default.default.on(this._element, EVENT_TOUCHEND, event => end(event));
for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {
EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault());
}
}
const endCallBack = () => {
if (this._config.pause !== 'hover') {
return;
}
// If it's a touch-enabled device, mouseenter/leave are fired as
// part of the mouse compatibility events on first tap - the carousel
// would stop cycling until user tapped out of it;
// here, we listen for touchend, explicitly pause the carousel
// (as if it's the second time we tap on it, mouseenter compat event
// is NOT fired) and after a timeout (to allow for mouse compatibility
// events to fire) we explicitly restart cycling
this.pause();
if (this.touchTimeout) {
clearTimeout(this.touchTimeout);
}
this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval);
};
const swipeConfig = {
leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),
rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),
endCallback: endCallBack
};
this._swipeHelper = new Swipe(this._element, swipeConfig);
}
_keydown(event) {
if (/input|textarea/i.test(event.target.tagName)) {
return;
}
const direction = KEY_TO_DIRECTION[event.key];
if (direction) {
event.preventDefault();
this._slide(direction);
this._slide(this._directionToOrder(direction));
}
}
_getItemIndex(element) {
this._items = element && element.parentNode ? SelectorEngine__default.default.find(SELECTOR_ITEM, element.parentNode) : [];
return this._items.indexOf(element);
return this._getItems().indexOf(element);
}
_getItemByOrder(order, activeElement) {
const isNext = order === ORDER_NEXT;
return getNextActiveElement(this._items, activeElement, isNext, this._config.wrap);
}
_triggerSlideEvent(relatedTarget, eventDirectionName) {
const targetIndex = this._getItemIndex(relatedTarget);
const fromIndex = this._getItemIndex(SelectorEngine__default.default.findOne(SELECTOR_ACTIVE_ITEM, this._element));
return EventHandler__default.default.trigger(this._element, EVENT_SLIDE, {
relatedTarget,
direction: eventDirectionName,
from: fromIndex,
to: targetIndex
});
}
_setActiveIndicatorElement(element) {
if (this._indicatorsElement) {
const activeIndicator = SelectorEngine__default.default.findOne(SELECTOR_ACTIVE, this._indicatorsElement);
activeIndicator.classList.remove(CLASS_NAME_ACTIVE);
activeIndicator.removeAttribute('aria-current');
const indicators = SelectorEngine__default.default.find(SELECTOR_INDICATOR, this._indicatorsElement);
for (let i = 0; i < indicators.length; i++) {
if (Number.parseInt(indicators[i].getAttribute('data-bs-slide-to'), 10) === this._getItemIndex(element)) {
indicators[i].classList.add(CLASS_NAME_ACTIVE);
indicators[i].setAttribute('aria-current', 'true');
break;
}
}
_setActiveIndicatorElement(index) {
if (!this._indicatorsElement) {
return;
}
const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement);
activeIndicator.classList.remove(CLASS_NAME_ACTIVE);
activeIndicator.removeAttribute('aria-current');
const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to="${index}"]`, this._indicatorsElement);
if (newActiveIndicator) {
newActiveIndicator.classList.add(CLASS_NAME_ACTIVE);
newActiveIndicator.setAttribute('aria-current', 'true');
}
}
_updateInterval() {
const element = this._activeElement || SelectorEngine__default.default.findOne(SELECTOR_ACTIVE_ITEM, this._element);
const element = this._activeElement || this._getActive();
if (!element) {
return;
}
const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10);
if (elementInterval) {
this._config.defaultInterval = this._config.defaultInterval || this._config.interval;
this._config.interval = elementInterval;
} else {
this._config.interval = this._config.defaultInterval || this._config.interval;
}
this._config.interval = elementInterval || this._config.defaultInterval;
}
_slide(directionOrOrder, element) {
const order = this._directionToOrder(directionOrOrder);
const activeElement = SelectorEngine__default.default.findOne(SELECTOR_ACTIVE_ITEM, this._element);
const activeElementIndex = this._getItemIndex(activeElement);
const nextElement = element || this._getItemByOrder(order, activeElement);
const nextElementIndex = this._getItemIndex(nextElement);
const isCycling = Boolean(this._interval);
const isNext = order === ORDER_NEXT;
const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END;
const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV;
const eventDirectionName = this._orderToDirection(order);
if (nextElement && nextElement.classList.contains(CLASS_NAME_ACTIVE)) {
this._isSliding = false;
return;
}
_slide(order, element = null) {
if (this._isSliding) {
return;
}
const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);
if (slideEvent.defaultPrevented) {
const activeElement = this._getActive();
const isNext = order === ORDER_NEXT;
const nextElement = element || index_js.getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap);
if (nextElement === activeElement) {
return;
}
if (!activeElement || !nextElement) {
// Some weirdness is happening, so we bail
return;
}
this._isSliding = true;
if (isCycling) {
this.pause();
}
this._setActiveIndicatorElement(nextElement);
this._activeElement = nextElement;
const triggerSlidEvent = () => {
EventHandler__default.default.trigger(this._element, EVENT_SLID, {
const nextElementIndex = this._getItemIndex(nextElement);
const triggerEvent = eventName => {
return EventHandler.trigger(this._element, eventName, {
relatedTarget: nextElement,
direction: eventDirectionName,
from: activeElementIndex,
direction: this._orderToDirection(order),
from: this._getItemIndex(activeElement),
to: nextElementIndex
});
};
if (this._element.classList.contains(CLASS_NAME_SLIDE)) {
nextElement.classList.add(orderClassName);
reflow(nextElement);
activeElement.classList.add(directionalClassName);
nextElement.classList.add(directionalClassName);
const completeCallBack = () => {
nextElement.classList.remove(directionalClassName, orderClassName);
nextElement.classList.add(CLASS_NAME_ACTIVE);
activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName);
this._isSliding = false;
setTimeout(triggerSlidEvent, 0);
};
this._queueCallback(completeCallBack, activeElement, true);
} else {
activeElement.classList.remove(CLASS_NAME_ACTIVE);
nextElement.classList.add(CLASS_NAME_ACTIVE);
this._isSliding = false;
triggerSlidEvent();
const slideEvent = triggerEvent(EVENT_SLIDE);
if (slideEvent.defaultPrevented) {
return;
}
if (!activeElement || !nextElement) {
// Some weirdness is happening, so we bail
// TODO: change tests that use empty divs to avoid this check
return;
}
const isCycling = Boolean(this._interval);
this.pause();
this._isSliding = true;
this._setActiveIndicatorElement(nextElementIndex);
this._activeElement = nextElement;
const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END;
const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV;
nextElement.classList.add(orderClassName);
index_js.reflow(nextElement);
activeElement.classList.add(directionalClassName);
nextElement.classList.add(directionalClassName);
const completeCallBack = () => {
nextElement.classList.remove(directionalClassName, orderClassName);
nextElement.classList.add(CLASS_NAME_ACTIVE);
activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName);
this._isSliding = false;
triggerEvent(EVENT_SLID);
};
this._queueCallback(completeCallBack, activeElement, this._isAnimated());
if (isCycling) {
this.cycle();
}
}
_directionToOrder(direction) {
if (![DIRECTION_RIGHT, DIRECTION_LEFT].includes(direction)) {
return direction;
_isAnimated() {
return this._element.classList.contains(CLASS_NAME_SLIDE);
}
_getActive() {
return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element);
}
_getItems() {
return SelectorEngine.find(SELECTOR_ITEM, this._element);
}
_clearInterval() {
if (this._interval) {
clearInterval(this._interval);
this._interval = null;
}
if (isRTL()) {
}
_directionToOrder(direction) {
if (index_js.isRTL()) {
return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT;
}
return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV;
}
_orderToDirection(order) {
if (![ORDER_NEXT, ORDER_PREV].includes(order)) {
return order;
}
if (isRTL()) {
if (index_js.isRTL()) {
return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT;
}
return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;
} // Static
static carouselInterface(element, config) {
const data = Carousel.getOrCreateInstance(element, config);
let {
_config
} = data;
if (typeof config === 'object') {
_config = { ..._config,
...config
};
}
const action = typeof config === 'string' ? config : _config.slide;
if (typeof config === 'number') {
data.to(config);
} else if (typeof action === 'string') {
if (typeof data[action] === 'undefined') {
throw new TypeError(`No method named "${action}"`);
}
data[action]();
} else if (_config.interval && _config.ride) {
data.pause();
data.cycle();
}
}
// Static
static jQueryInterface(config) {
return this.each(function () {
Carousel.carouselInterface(this, config);
const data = Carousel.getOrCreateInstance(this, config);
if (typeof config === 'number') {
data.to(config);
return;
}
if (typeof config === 'string') {
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
}
});
}
static dataApiClickHandler(event) {
const target = getElementFromSelector(this);
if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {
return;
}
const config = { ...Manipulator__default.default.getDataAttributes(target),
...Manipulator__default.default.getDataAttributes(this)
};
const slideIndex = this.getAttribute('data-bs-slide-to');
if (slideIndex) {
config.interval = false;
}
Carousel.carouselInterface(target, config);
if (slideIndex) {
Carousel.getInstance(target).to(slideIndex);
}
event.preventDefault();
}
}
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
* Data API implementation
*/
EventHandler__default.default.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel.dataApiClickHandler);
EventHandler__default.default.on(window, EVENT_LOAD_DATA_API, () => {
const carousels = SelectorEngine__default.default.find(SELECTOR_DATA_RIDE);
for (let i = 0, len = carousels.length; i < len; i++) {
Carousel.carouselInterface(carousels[i], Carousel.getInstance(carousels[i]));
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {
const target = SelectorEngine.getElementFromSelector(this);
if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {
return;
}
event.preventDefault();
const carousel = Carousel.getOrCreateInstance(target);
const slideIndex = this.getAttribute('data-bs-slide-to');
if (slideIndex) {
carousel.to(slideIndex);
carousel._maybeEnableCycle();
return;
}
if (Manipulator.getDataAttribute(this, 'slide') === 'next') {
carousel.next();
carousel._maybeEnableCycle();
return;
}
carousel.prev();
carousel._maybeEnableCycle();
});
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE);
for (const carousel of carousels) {
Carousel.getOrCreateInstance(carousel);
}
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .Carousel to jQuery only if jQuery is present
*/
defineJQueryPlugin(Carousel);
index_js.defineJQueryPlugin(Carousel);
return Carousel;

View file

@ -1,199 +1,30 @@
/*!
* Bootstrap collapse.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap collapse.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/data.js'), require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./base-component.js')) :
typeof define === 'function' && define.amd ? define(['./dom/data', './dom/event-handler', './dom/manipulator', './dom/selector-engine', './base-component'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Collapse = factory(global.Data, global.EventHandler, global.Manipulator, global.SelectorEngine, global.Base));
})(this, (function (Data, EventHandler, Manipulator, SelectorEngine, BaseComponent) { 'use strict';
const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
const Data__default = /*#__PURE__*/_interopDefaultLegacy(Data);
const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
const Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
const SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./dom/selector-engine.js'), require('./util/index.js')) :
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './dom/selector-engine', './util/index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Collapse = factory(global.BaseComponent, global.EventHandler, global.SelectorEngine, global.Index));
})(this, (function (BaseComponent, EventHandler, SelectorEngine, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Bootstrap collapse.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const toType = obj => {
if (obj === null || obj === undefined) {
return `${obj}`;
}
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
};
const getSelector = element => {
let selector = element.getAttribute('data-bs-target');
if (!selector || selector === '#') {
let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
// so everything starting with `#` or `.`. If a "real" URL is used as the selector,
// `document.querySelector` will rightfully complain it is invalid.
// See https://github.com/twbs/bootstrap/issues/32273
if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
return null;
} // Just in case some CMS puts out a full URL with the anchor appended
if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
hrefAttr = `#${hrefAttr.split('#')[1]}`;
}
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
}
return selector;
};
const getSelectorFromElement = element => {
const selector = getSelector(element);
if (selector) {
return document.querySelector(selector) ? selector : null;
}
return null;
};
const getElementFromSelector = element => {
const selector = getSelector(element);
return selector ? document.querySelector(selector) : null;
};
const isElement = obj => {
if (!obj || typeof obj !== 'object') {
return false;
}
if (typeof obj.jquery !== 'undefined') {
obj = obj[0];
}
return typeof obj.nodeType !== 'undefined';
};
const getElement = obj => {
if (isElement(obj)) {
// it's a jQuery object or a node element
return obj.jquery ? obj[0] : obj;
}
if (typeof obj === 'string' && obj.length > 0) {
return document.querySelector(obj);
}
return null;
};
const typeCheckConfig = (componentName, config, configTypes) => {
Object.keys(configTypes).forEach(property => {
const expectedTypes = configTypes[property];
const value = config[property];
const valueType = value && isElement(value) ? 'element' : toType(value);
if (!new RegExp(expectedTypes).test(valueType)) {
throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
}
});
};
/**
* Trick to restart an element's animation
*
* @param {HTMLElement} element
* @return void
*
* @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
*/
const reflow = element => {
// eslint-disable-next-line no-unused-expressions
element.offsetHeight;
};
const getjQuery = () => {
const {
jQuery
} = window;
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
return jQuery;
}
return null;
};
const DOMContentLoadedCallbacks = [];
const onDOMContentLoaded = callback => {
if (document.readyState === 'loading') {
// add listener on the first call when the document is in loading state
if (!DOMContentLoadedCallbacks.length) {
document.addEventListener('DOMContentLoaded', () => {
DOMContentLoadedCallbacks.forEach(callback => callback());
});
}
DOMContentLoadedCallbacks.push(callback);
} else {
callback();
}
};
const defineJQueryPlugin = plugin => {
onDOMContentLoaded(() => {
const $ = getjQuery();
/* istanbul ignore if */
if ($) {
const name = plugin.NAME;
const JQUERY_NO_CONFLICT = $.fn[name];
$.fn[name] = plugin.jQueryInterface;
$.fn[name].Constructor = plugin;
$.fn[name].noConflict = () => {
$.fn[name] = JQUERY_NO_CONFLICT;
return plugin.jQueryInterface;
};
}
});
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): collapse.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'collapse';
const DATA_KEY = 'bs.collapse';
const EVENT_KEY = `.${DATA_KEY}`;
const DATA_API_KEY = '.data-api';
const Default = {
toggle: true,
parent: null
};
const DefaultType = {
toggle: 'boolean',
parent: '(null|element)'
};
const EVENT_SHOW = `show${EVENT_KEY}`;
const EVENT_SHOWN = `shown${EVENT_KEY}`;
const EVENT_HIDE = `hide${EVENT_KEY}`;
@ -209,53 +40,53 @@
const HEIGHT = 'height';
const SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing';
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="collapse"]';
const Default = {
parent: null,
toggle: true
};
const DefaultType = {
parent: '(null|element)',
toggle: 'boolean'
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
* Class definition
*/
class Collapse extends BaseComponent__default.default {
class Collapse extends BaseComponent {
constructor(element, config) {
super(element);
super(element, config);
this._isTransitioning = false;
this._config = this._getConfig(config);
this._triggerArray = [];
const toggleList = SelectorEngine__default.default.find(SELECTOR_DATA_TOGGLE);
for (let i = 0, len = toggleList.length; i < len; i++) {
const elem = toggleList[i];
const selector = getSelectorFromElement(elem);
const filterElement = SelectorEngine__default.default.find(selector).filter(foundElem => foundElem === this._element);
const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE);
for (const elem of toggleList) {
const selector = SelectorEngine.getSelectorFromElement(elem);
const filterElement = SelectorEngine.find(selector).filter(foundElement => foundElement === this._element);
if (selector !== null && filterElement.length) {
this._selector = selector;
this._triggerArray.push(elem);
}
}
this._initializeChildren();
if (!this._config.parent) {
this._addAriaAndCollapsedClass(this._triggerArray, this._isShown());
}
if (this._config.toggle) {
this.toggle();
}
} // Getters
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
} // Public
}
// Public
toggle() {
if (this._isShown()) {
this.hide();
@ -263,231 +94,154 @@
this.show();
}
}
show() {
if (this._isTransitioning || this._isShown()) {
return;
}
let activeChildren = [];
let actives = [];
let activesData;
// find active children
if (this._config.parent) {
const children = SelectorEngine__default.default.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent);
actives = SelectorEngine__default.default.find(SELECTOR_ACTIVES, this._config.parent).filter(elem => !children.includes(elem)); // remove children if greater depth
activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES).filter(element => element !== this._element).map(element => Collapse.getOrCreateInstance(element, {
toggle: false
}));
}
const container = SelectorEngine__default.default.findOne(this._selector);
if (actives.length) {
const tempActiveData = actives.find(elem => container !== elem);
activesData = tempActiveData ? Collapse.getInstance(tempActiveData) : null;
if (activesData && activesData._isTransitioning) {
return;
}
if (activeChildren.length && activeChildren[0]._isTransitioning) {
return;
}
const startEvent = EventHandler__default.default.trigger(this._element, EVENT_SHOW);
const startEvent = EventHandler.trigger(this._element, EVENT_SHOW);
if (startEvent.defaultPrevented) {
return;
}
actives.forEach(elemActive => {
if (container !== elemActive) {
Collapse.getOrCreateInstance(elemActive, {
toggle: false
}).hide();
}
if (!activesData) {
Data__default.default.set(elemActive, DATA_KEY, null);
}
});
for (const activeInstance of activeChildren) {
activeInstance.hide();
}
const dimension = this._getDimension();
this._element.classList.remove(CLASS_NAME_COLLAPSE);
this._element.classList.add(CLASS_NAME_COLLAPSING);
this._element.style[dimension] = 0;
this._addAriaAndCollapsedClass(this._triggerArray, true);
this._isTransitioning = true;
const complete = () => {
this._isTransitioning = false;
this._element.classList.remove(CLASS_NAME_COLLAPSING);
this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW);
this._element.style[dimension] = '';
EventHandler__default.default.trigger(this._element, EVENT_SHOWN);
EventHandler.trigger(this._element, EVENT_SHOWN);
};
const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
const scrollSize = `scroll${capitalizedDimension}`;
this._queueCallback(complete, this._element, true);
this._element.style[dimension] = `${this._element[scrollSize]}px`;
}
hide() {
if (this._isTransitioning || !this._isShown()) {
return;
}
const startEvent = EventHandler__default.default.trigger(this._element, EVENT_HIDE);
const startEvent = EventHandler.trigger(this._element, EVENT_HIDE);
if (startEvent.defaultPrevented) {
return;
}
const dimension = this._getDimension();
this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`;
reflow(this._element);
index_js.reflow(this._element);
this._element.classList.add(CLASS_NAME_COLLAPSING);
this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW);
const triggerArrayLength = this._triggerArray.length;
for (let i = 0; i < triggerArrayLength; i++) {
const trigger = this._triggerArray[i];
const elem = getElementFromSelector(trigger);
if (elem && !this._isShown(elem)) {
for (const trigger of this._triggerArray) {
const element = SelectorEngine.getElementFromSelector(trigger);
if (element && !this._isShown(element)) {
this._addAriaAndCollapsedClass([trigger], false);
}
}
this._isTransitioning = true;
const complete = () => {
this._isTransitioning = false;
this._element.classList.remove(CLASS_NAME_COLLAPSING);
this._element.classList.add(CLASS_NAME_COLLAPSE);
EventHandler__default.default.trigger(this._element, EVENT_HIDDEN);
EventHandler.trigger(this._element, EVENT_HIDDEN);
};
this._element.style[dimension] = '';
this._queueCallback(complete, this._element, true);
}
_isShown(element = this._element) {
return element.classList.contains(CLASS_NAME_SHOW);
} // Private
_getConfig(config) {
config = { ...Default,
...Manipulator__default.default.getDataAttributes(this._element),
...config
};
config.toggle = Boolean(config.toggle); // Coerce string values
config.parent = getElement(config.parent);
typeCheckConfig(NAME, config, DefaultType);
return config;
}
// Private
_configAfterMerge(config) {
config.toggle = Boolean(config.toggle); // Coerce string values
config.parent = index_js.getElement(config.parent);
return config;
}
_getDimension() {
return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT;
}
_initializeChildren() {
if (!this._config.parent) {
return;
}
const children = SelectorEngine__default.default.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent);
SelectorEngine__default.default.find(SELECTOR_DATA_TOGGLE, this._config.parent).filter(elem => !children.includes(elem)).forEach(element => {
const selected = getElementFromSelector(element);
const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE);
for (const element of children) {
const selected = SelectorEngine.getElementFromSelector(element);
if (selected) {
this._addAriaAndCollapsedClass([element], this._isShown(selected));
}
});
}
}
_getFirstLevelChildren(selector) {
const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent);
// remove children if greater depth
return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element));
}
_addAriaAndCollapsedClass(triggerArray, isOpen) {
if (!triggerArray.length) {
return;
}
for (const element of triggerArray) {
element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen);
element.setAttribute('aria-expanded', isOpen);
}
}
triggerArray.forEach(elem => {
if (isOpen) {
elem.classList.remove(CLASS_NAME_COLLAPSED);
} else {
elem.classList.add(CLASS_NAME_COLLAPSED);
}
elem.setAttribute('aria-expanded', isOpen);
});
} // Static
// Static
static jQueryInterface(config) {
const _config = {};
if (typeof config === 'string' && /show|hide/.test(config)) {
_config.toggle = false;
}
return this.each(function () {
const _config = {};
if (typeof config === 'string' && /show|hide/.test(config)) {
_config.toggle = false;
}
const data = Collapse.getOrCreateInstance(this, _config);
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
}
});
}
}
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
* Data API implementation
*/
EventHandler__default.default.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
// preventDefault only for <a> elements (which change the URL) not inside the collapsible element
if (event.target.tagName === 'A' || event.delegateTarget && event.delegateTarget.tagName === 'A') {
event.preventDefault();
}
const selector = getSelectorFromElement(this);
const selectorElements = SelectorEngine__default.default.find(selector);
selectorElements.forEach(element => {
for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {
Collapse.getOrCreateInstance(element, {
toggle: false
}).toggle();
});
}
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .Collapse to jQuery only if jQuery is present
*/
defineJQueryPlugin(Collapse);
index_js.defineJQueryPlugin(Collapse);
return Collapse;

View file

@ -1,6 +1,6 @@
/*!
* Bootstrap data.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap data.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
@ -11,56 +11,50 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): dom/data.js
* Bootstrap dom/data.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const elementMap = new Map();
const data = {
set(element, key, instance) {
if (!elementMap.has(element)) {
elementMap.set(element, new Map());
}
const instanceMap = elementMap.get(element);
const instanceMap = elementMap.get(element); // make it clear we only want one instance per element
// make it clear we only want one instance per element
// can be removed later when multiple key/instances are fine to be used
if (!instanceMap.has(key) && instanceMap.size !== 0) {
// eslint-disable-next-line no-console
console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`);
return;
}
instanceMap.set(key, instance);
},
get(element, key) {
if (elementMap.has(element)) {
return elementMap.get(element).get(key) || null;
}
return null;
},
remove(element, key) {
if (!elementMap.has(element)) {
return;
}
const instanceMap = elementMap.get(element);
instanceMap.delete(key); // free up element references if there are no instances left for an element
instanceMap.delete(key);
// free up element references if there are no instances left for an element
if (instanceMap.size === 0) {
elementMap.delete(element);
}
}
};
return data;

View file

@ -1,274 +1,197 @@
/*!
* Bootstrap event-handler.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap event-handler.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.EventHandler = factory());
})(this, (function () { 'use strict';
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../util/index.js')) :
typeof define === 'function' && define.amd ? define(['../util/index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.EventHandler = factory(global.Index));
})(this, (function (index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Bootstrap dom/event-handler.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const getjQuery = () => {
const {
jQuery
} = window;
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
return jQuery;
}
return null;
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): dom/event-handler.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const namespaceRegex = /[^.]*(?=\..*)\.|.*/;
const stripNameRegex = /\..*/;
const stripUidRegex = /::\d+$/;
const eventRegistry = {}; // Events storage
let uidEvent = 1;
const customEvents = {
mouseenter: 'mouseover',
mouseleave: 'mouseout'
};
const customEventsRegex = /^(mouseenter|mouseleave)/i;
const nativeEvents = new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focusout', 'load', 'unload', 'beforeunload', 'resize', 'move', 'DOMContentLoaded', 'readystatechange', 'error', 'abort', 'scroll']);
/**
* ------------------------------------------------------------------------
* Private methods
* ------------------------------------------------------------------------
*/
function getUidEvent(element, uid) {
function makeEventUid(element, uid) {
return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++;
}
function getEvent(element) {
const uid = getUidEvent(element);
function getElementEvents(element) {
const uid = makeEventUid(element);
element.uidEvent = uid;
eventRegistry[uid] = eventRegistry[uid] || {};
return eventRegistry[uid];
}
function bootstrapHandler(element, fn) {
return function handler(event) {
event.delegateTarget = element;
hydrateObj(event, {
delegateTarget: element
});
if (handler.oneOff) {
EventHandler.off(element, event.type, fn);
}
return fn.apply(element, [event]);
};
}
function bootstrapDelegationHandler(element, selector, fn) {
return function handler(event) {
const domElements = element.querySelectorAll(selector);
for (let {
target
} = event; target && target !== this; target = target.parentNode) {
for (let i = domElements.length; i--;) {
if (domElements[i] === target) {
event.delegateTarget = target;
if (handler.oneOff) {
EventHandler.off(element, event.type, selector, fn);
}
return fn.apply(target, [event]);
for (const domElement of domElements) {
if (domElement !== target) {
continue;
}
hydrateObj(event, {
delegateTarget: target
});
if (handler.oneOff) {
EventHandler.off(element, event.type, selector, fn);
}
return fn.apply(target, [event]);
}
} // To please ESLint
return null;
}
};
}
function findHandler(events, handler, delegationSelector = null) {
const uidEventList = Object.keys(events);
for (let i = 0, len = uidEventList.length; i < len; i++) {
const event = events[uidEventList[i]];
if (event.originalHandler === handler && event.delegationSelector === delegationSelector) {
return event;
}
}
return null;
function findHandler(events, callable, delegationSelector = null) {
return Object.values(events).find(event => event.callable === callable && event.delegationSelector === delegationSelector);
}
function normalizeParams(originalTypeEvent, handler, delegationFn) {
const delegation = typeof handler === 'string';
const originalHandler = delegation ? delegationFn : handler;
function normalizeParameters(originalTypeEvent, handler, delegationFunction) {
const isDelegated = typeof handler === 'string';
// TODO: tooltip passes `false` instead of selector, so we need to check
const callable = isDelegated ? delegationFunction : handler || delegationFunction;
let typeEvent = getTypeEvent(originalTypeEvent);
const isNative = nativeEvents.has(typeEvent);
if (!isNative) {
if (!nativeEvents.has(typeEvent)) {
typeEvent = originalTypeEvent;
}
return [delegation, originalHandler, typeEvent];
return [isDelegated, callable, typeEvent];
}
function addHandler(element, originalTypeEvent, handler, delegationFn, oneOff) {
function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {
if (typeof originalTypeEvent !== 'string' || !element) {
return;
}
let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);
if (!handler) {
handler = delegationFn;
delegationFn = null;
} // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position
// in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position
// this prevents the handler from being dispatched the same way as mouseover or mouseout does
if (customEventsRegex.test(originalTypeEvent)) {
const wrapFn = fn => {
if (originalTypeEvent in customEvents) {
const wrapFunction = fn => {
return function (event) {
if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) {
return fn.call(this, event);
}
};
};
if (delegationFn) {
delegationFn = wrapFn(delegationFn);
} else {
handler = wrapFn(handler);
}
callable = wrapFunction(callable);
}
const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn);
const events = getEvent(element);
const events = getElementEvents(element);
const handlers = events[typeEvent] || (events[typeEvent] = {});
const previousFn = findHandler(handlers, originalHandler, delegation ? handler : null);
if (previousFn) {
previousFn.oneOff = previousFn.oneOff && oneOff;
const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null);
if (previousFunction) {
previousFunction.oneOff = previousFunction.oneOff && oneOff;
return;
}
const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, ''));
const fn = delegation ? bootstrapDelegationHandler(element, handler, delegationFn) : bootstrapHandler(element, handler);
fn.delegationSelector = delegation ? handler : null;
fn.originalHandler = originalHandler;
const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''));
const fn = isDelegated ? bootstrapDelegationHandler(element, handler, callable) : bootstrapHandler(element, callable);
fn.delegationSelector = isDelegated ? handler : null;
fn.callable = callable;
fn.oneOff = oneOff;
fn.uidEvent = uid;
handlers[uid] = fn;
element.addEventListener(typeEvent, fn, delegation);
element.addEventListener(typeEvent, fn, isDelegated);
}
function removeHandler(element, events, typeEvent, handler, delegationSelector) {
const fn = findHandler(events[typeEvent], handler, delegationSelector);
if (!fn) {
return;
}
element.removeEventListener(typeEvent, fn, Boolean(delegationSelector));
delete events[typeEvent][fn.uidEvent];
}
function removeNamespacedHandlers(element, events, typeEvent, namespace) {
const storeElementEvent = events[typeEvent] || {};
Object.keys(storeElementEvent).forEach(handlerKey => {
for (const [handlerKey, event] of Object.entries(storeElementEvent)) {
if (handlerKey.includes(namespace)) {
const event = storeElementEvent[handlerKey];
removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector);
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);
}
});
}
}
function getTypeEvent(event) {
// allow to get the native events from namespaced events ('click.bs.button' --> 'click')
event = event.replace(stripNameRegex, '');
return customEvents[event] || event;
}
const EventHandler = {
on(element, event, handler, delegationFn) {
addHandler(element, event, handler, delegationFn, false);
on(element, event, handler, delegationFunction) {
addHandler(element, event, handler, delegationFunction, false);
},
one(element, event, handler, delegationFn) {
addHandler(element, event, handler, delegationFn, true);
one(element, event, handler, delegationFunction) {
addHandler(element, event, handler, delegationFunction, true);
},
off(element, originalTypeEvent, handler, delegationFn) {
off(element, originalTypeEvent, handler, delegationFunction) {
if (typeof originalTypeEvent !== 'string' || !element) {
return;
}
const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn);
const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);
const inNamespace = typeEvent !== originalTypeEvent;
const events = getEvent(element);
const events = getElementEvents(element);
const storeElementEvent = events[typeEvent] || {};
const isNamespace = originalTypeEvent.startsWith('.');
if (typeof originalHandler !== 'undefined') {
if (typeof callable !== 'undefined') {
// Simplest case: handler is passed, remove that listener ONLY.
if (!events || !events[typeEvent]) {
if (!Object.keys(storeElementEvent).length) {
return;
}
removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null);
removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null);
return;
}
if (isNamespace) {
Object.keys(events).forEach(elementEvent => {
for (const elementEvent of Object.keys(events)) {
removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1));
});
}
const storeElementEvent = events[typeEvent] || {};
Object.keys(storeElementEvent).forEach(keyHandlers => {
const handlerKey = keyHandlers.replace(stripUidRegex, '');
if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
const event = storeElementEvent[keyHandlers];
removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector);
}
});
}
for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {
const handlerKey = keyHandlers.replace(stripUidRegex, '');
if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);
}
}
},
trigger(element, event, args) {
if (typeof event !== 'string' || !element) {
return null;
}
const $ = getjQuery();
const $ = index_js.getjQuery();
const typeEvent = getTypeEvent(event);
const inNamespace = event !== typeEvent;
const isNative = nativeEvents.has(typeEvent);
let jQueryEvent;
let jQueryEvent = null;
let bubbles = true;
let nativeDispatch = true;
let defaultPrevented = false;
let evt = null;
if (inNamespace && $) {
jQueryEvent = $.Event(event, args);
$(element).trigger(jQueryEvent);
@ -276,45 +199,37 @@
nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();
defaultPrevented = jQueryEvent.isDefaultPrevented();
}
if (isNative) {
evt = document.createEvent('HTMLEvents');
evt.initEvent(typeEvent, bubbles, true);
} else {
evt = new CustomEvent(event, {
bubbles,
cancelable: true
});
} // merge custom information in our event
if (typeof args !== 'undefined') {
Object.keys(args).forEach(key => {
Object.defineProperty(evt, key, {
get() {
return args[key];
}
});
});
}
const evt = hydrateObj(new Event(event, {
bubbles,
cancelable: true
}), args);
if (defaultPrevented) {
evt.preventDefault();
}
if (nativeDispatch) {
element.dispatchEvent(evt);
}
if (evt.defaultPrevented && typeof jQueryEvent !== 'undefined') {
if (evt.defaultPrevented && jQueryEvent) {
jQueryEvent.preventDefault();
}
return evt;
}
};
function hydrateObj(obj, meta = {}) {
for (const [key, value] of Object.entries(meta)) {
try {
obj[key] = value;
} catch (_unused) {
Object.defineProperty(obj, key, {
configurable: true,
get() {
return value;
}
});
}
}
return obj;
}
return EventHandler;

View file

@ -1,6 +1,6 @@
/*!
* Bootstrap manipulator.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap manipulator.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
@ -11,76 +11,59 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): dom/manipulator.js
* Bootstrap dom/manipulator.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
function normalizeData(val) {
if (val === 'true') {
function normalizeData(value) {
if (value === 'true') {
return true;
}
if (val === 'false') {
if (value === 'false') {
return false;
}
if (val === Number(val).toString()) {
return Number(val);
if (value === Number(value).toString()) {
return Number(value);
}
if (val === '' || val === 'null') {
if (value === '' || value === 'null') {
return null;
}
return val;
if (typeof value !== 'string') {
return value;
}
try {
return JSON.parse(decodeURIComponent(value));
} catch (_unused) {
return value;
}
}
function normalizeDataKey(key) {
return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`);
}
const Manipulator = {
setDataAttribute(element, key, value) {
element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value);
},
removeDataAttribute(element, key) {
element.removeAttribute(`data-bs-${normalizeDataKey(key)}`);
},
getDataAttributes(element) {
if (!element) {
return {};
}
const attributes = {};
Object.keys(element.dataset).filter(key => key.startsWith('bs')).forEach(key => {
const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'));
for (const key of bsKeys) {
let pureKey = key.replace(/^bs/, '');
pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length);
attributes[pureKey] = normalizeData(element.dataset[key]);
});
}
return attributes;
},
getDataAttribute(element, key) {
return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`));
},
offset(element) {
const rect = element.getBoundingClientRect();
return {
top: rect.top + window.pageYOffset,
left: rect.left + window.pageXOffset
};
},
position(element) {
return {
top: element.offsetTop,
left: element.offsetLeft
};
}
};
return Manipulator;

View file

@ -1,125 +1,101 @@
/*!
* Bootstrap selector-engine.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap selector-engine.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.SelectorEngine = factory());
})(this, (function () { 'use strict';
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../util/index.js')) :
typeof define === 'function' && define.amd ? define(['../util/index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.SelectorEngine = factory(global.Index));
})(this, (function (index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Bootstrap dom/selector-engine.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const isElement = obj => {
if (!obj || typeof obj !== 'object') {
return false;
}
const getSelector = element => {
let selector = element.getAttribute('data-bs-target');
if (!selector || selector === '#') {
let hrefAttribute = element.getAttribute('href');
if (typeof obj.jquery !== 'undefined') {
obj = obj[0];
}
// The only valid content that could double as a selector are IDs or classes,
// so everything starting with `#` or `.`. If a "real" URL is used as the selector,
// `document.querySelector` will rightfully complain it is invalid.
// See https://github.com/twbs/bootstrap/issues/32273
if (!hrefAttribute || !hrefAttribute.includes('#') && !hrefAttribute.startsWith('.')) {
return null;
}
return typeof obj.nodeType !== 'undefined';
// Just in case some CMS puts out a full URL with the anchor appended
if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {
hrefAttribute = `#${hrefAttribute.split('#')[1]}`;
}
selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null;
}
return selector ? selector.split(',').map(sel => index_js.parseSelector(sel)).join(',') : null;
};
const isVisible = element => {
if (!isElement(element) || element.getClientRects().length === 0) {
return false;
}
return getComputedStyle(element).getPropertyValue('visibility') === 'visible';
};
const isDisabled = element => {
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
return true;
}
if (element.classList.contains('disabled')) {
return true;
}
if (typeof element.disabled !== 'undefined') {
return element.disabled;
}
return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): dom/selector-engine.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const NODE_TEXT = 3;
const SelectorEngine = {
find(selector, element = document.documentElement) {
return [].concat(...Element.prototype.querySelectorAll.call(element, selector));
},
findOne(selector, element = document.documentElement) {
return Element.prototype.querySelector.call(element, selector);
},
children(element, selector) {
return [].concat(...element.children).filter(child => child.matches(selector));
},
parents(element, selector) {
const parents = [];
let ancestor = element.parentNode;
while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE && ancestor.nodeType !== NODE_TEXT) {
if (ancestor.matches(selector)) {
parents.push(ancestor);
}
ancestor = ancestor.parentNode;
let ancestor = element.parentNode.closest(selector);
while (ancestor) {
parents.push(ancestor);
ancestor = ancestor.parentNode.closest(selector);
}
return parents;
},
prev(element, selector) {
let previous = element.previousElementSibling;
while (previous) {
if (previous.matches(selector)) {
return [previous];
}
previous = previous.previousElementSibling;
}
return [];
},
// TODO: this is now unused; remove later along with prev()
next(element, selector) {
let next = element.nextElementSibling;
while (next) {
if (next.matches(selector)) {
return [next];
}
next = next.nextElementSibling;
}
return [];
},
focusableChildren(element) {
const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable="true"]'].map(selector => `${selector}:not([tabindex^="-"])`).join(', ');
return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el));
const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable="true"]'].map(selector => `${selector}:not([tabindex^="-"])`).join(',');
return this.find(focusables, element).filter(el => !index_js.isDisabled(el) && index_js.isVisible(el));
},
getSelectorFromElement(element) {
const selector = getSelector(element);
if (selector) {
return SelectorEngine.findOne(selector) ? selector : null;
}
return null;
},
getElementFromSelector(element) {
const selector = getSelector(element);
return selector ? SelectorEngine.findOne(selector) : null;
},
getMultipleElementsFromSelector(element) {
const selector = getSelector(element);
return selector ? SelectorEngine.find(selector) : [];
}
};
return SelectorEngine;

View file

@ -1,19 +1,16 @@
/*!
* Bootstrap dropdown.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap dropdown.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@popperjs/core'), require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./base-component.js')) :
typeof define === 'function' && define.amd ? define(['@popperjs/core', './dom/event-handler', './dom/manipulator', './dom/selector-engine', './base-component'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Dropdown = factory(global.Popper, global.EventHandler, global.Manipulator, global.SelectorEngine, global.Base));
})(this, (function (Popper, EventHandler, Manipulator, SelectorEngine, BaseComponent) { 'use strict';
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@popperjs/core'), require('./base-component.js'), require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./util/index.js')) :
typeof define === 'function' && define.amd ? define(['@popperjs/core', './base-component', './dom/event-handler', './dom/manipulator', './dom/selector-engine', './util/index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Dropdown = factory(global.Popper, global.BaseComponent, global.EventHandler, global.Manipulator, global.SelectorEngine, global.Index));
})(this, (function (Popper, BaseComponent, EventHandler, Manipulator, SelectorEngine, index_js) { 'use strict';
const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
function _interopNamespace(e) {
if (e && e.__esModule) return e;
const n = Object.create(null);
function _interopNamespaceDefault(e) {
const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
if (e) {
for (const k in e) {
if (k !== 'default') {
@ -29,206 +26,18 @@
return Object.freeze(n);
}
const Popper__namespace = /*#__PURE__*/_interopNamespace(Popper);
const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
const Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
const SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
const Popper__namespace = /*#__PURE__*/_interopNamespaceDefault(Popper);
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Bootstrap dropdown.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const toType = obj => {
if (obj === null || obj === undefined) {
return `${obj}`;
}
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
};
const getSelector = element => {
let selector = element.getAttribute('data-bs-target');
if (!selector || selector === '#') {
let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
// so everything starting with `#` or `.`. If a "real" URL is used as the selector,
// `document.querySelector` will rightfully complain it is invalid.
// See https://github.com/twbs/bootstrap/issues/32273
if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
return null;
} // Just in case some CMS puts out a full URL with the anchor appended
if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
hrefAttr = `#${hrefAttr.split('#')[1]}`;
}
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
}
return selector;
};
const getElementFromSelector = element => {
const selector = getSelector(element);
return selector ? document.querySelector(selector) : null;
};
const isElement = obj => {
if (!obj || typeof obj !== 'object') {
return false;
}
if (typeof obj.jquery !== 'undefined') {
obj = obj[0];
}
return typeof obj.nodeType !== 'undefined';
};
const getElement = obj => {
if (isElement(obj)) {
// it's a jQuery object or a node element
return obj.jquery ? obj[0] : obj;
}
if (typeof obj === 'string' && obj.length > 0) {
return document.querySelector(obj);
}
return null;
};
const typeCheckConfig = (componentName, config, configTypes) => {
Object.keys(configTypes).forEach(property => {
const expectedTypes = configTypes[property];
const value = config[property];
const valueType = value && isElement(value) ? 'element' : toType(value);
if (!new RegExp(expectedTypes).test(valueType)) {
throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
}
});
};
const isVisible = element => {
if (!isElement(element) || element.getClientRects().length === 0) {
return false;
}
return getComputedStyle(element).getPropertyValue('visibility') === 'visible';
};
const isDisabled = element => {
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
return true;
}
if (element.classList.contains('disabled')) {
return true;
}
if (typeof element.disabled !== 'undefined') {
return element.disabled;
}
return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
};
const noop = () => {};
const getjQuery = () => {
const {
jQuery
} = window;
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
return jQuery;
}
return null;
};
const DOMContentLoadedCallbacks = [];
const onDOMContentLoaded = callback => {
if (document.readyState === 'loading') {
// add listener on the first call when the document is in loading state
if (!DOMContentLoadedCallbacks.length) {
document.addEventListener('DOMContentLoaded', () => {
DOMContentLoadedCallbacks.forEach(callback => callback());
});
}
DOMContentLoadedCallbacks.push(callback);
} else {
callback();
}
};
const isRTL = () => document.documentElement.dir === 'rtl';
const defineJQueryPlugin = plugin => {
onDOMContentLoaded(() => {
const $ = getjQuery();
/* istanbul ignore if */
if ($) {
const name = plugin.NAME;
const JQUERY_NO_CONFLICT = $.fn[name];
$.fn[name] = plugin.jQueryInterface;
$.fn[name].Constructor = plugin;
$.fn[name].noConflict = () => {
$.fn[name] = JQUERY_NO_CONFLICT;
return plugin.jQueryInterface;
};
}
});
};
/**
* Return the previous/next element of a list.
*
* @param {array} list The list of elements
* @param activeElement The active element
* @param shouldGetNext Choose to get next or previous element
* @param isCycleAllowed
* @return {Element|elem} The proper element
*/
const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
let index = list.indexOf(activeElement); // if the element does not exist in the list return an element depending on the direction and if cycle is allowed
if (index === -1) {
return list[!shouldGetNext && isCycleAllowed ? list.length - 1 : 0];
}
const listLength = list.length;
index += shouldGetNext ? 1 : -1;
if (isCycleAllowed) {
index = (index + listLength) % listLength;
}
return list[Math.max(0, Math.min(index, listLength - 1))];
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): dropdown.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'dropdown';
@ -236,13 +45,11 @@
const EVENT_KEY = `.${DATA_KEY}`;
const DATA_API_KEY = '.data-api';
const ESCAPE_KEY = 'Escape';
const SPACE_KEY = 'Space';
const TAB_KEY = 'Tab';
const ARROW_UP_KEY = 'ArrowUp';
const ARROW_DOWN_KEY = 'ArrowDown';
const RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button
const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEY}|${ARROW_DOWN_KEY}|${ESCAPE_KEY}`);
const EVENT_HIDE = `hide${EVENT_KEY}`;
const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
const EVENT_SHOW = `show${EVENT_KEY}`;
@ -254,253 +61,205 @@
const CLASS_NAME_DROPUP = 'dropup';
const CLASS_NAME_DROPEND = 'dropend';
const CLASS_NAME_DROPSTART = 'dropstart';
const CLASS_NAME_NAVBAR = 'navbar';
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]';
const SELECTOR_MENU = '.dropdown-menu:not(.o-dropdown--menu)';
const CLASS_NAME_DROPUP_CENTER = 'dropup-center';
const CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center';
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)';
const SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`;
const SELECTOR_MENU = '.dropdown-menu:not(.o-dropdown--menu)'; // Odoo fix task-2764821
const SELECTOR_NAVBAR = '.navbar';
const SELECTOR_MENU_NOT_SUB = '.dropdown-menu:not(.o-dropdown--menu):not(.o_wysiwyg_submenu)';
const SELECTOR_NAVBAR_NAV = '.navbar-nav';
const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)';
const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start';
const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end';
const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start';
const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end';
const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start';
const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start';
const PLACEMENT_TOP = index_js.isRTL() ? 'top-end' : 'top-start';
const PLACEMENT_TOPEND = index_js.isRTL() ? 'top-start' : 'top-end';
const PLACEMENT_BOTTOM = index_js.isRTL() ? 'bottom-end' : 'bottom-start';
const PLACEMENT_BOTTOMEND = index_js.isRTL() ? 'bottom-start' : 'bottom-end';
const PLACEMENT_RIGHT = index_js.isRTL() ? 'left-start' : 'right-start';
const PLACEMENT_LEFT = index_js.isRTL() ? 'right-start' : 'left-start';
const PLACEMENT_TOPCENTER = 'top';
const PLACEMENT_BOTTOMCENTER = 'bottom';
const Default = {
offset: [0, 2],
autoClose: true,
boundary: 'clippingParents',
reference: 'toggle',
display: 'dynamic',
offset: [0, 2],
popperConfig: null,
autoClose: true
reference: 'toggle'
};
const DefaultType = {
offset: '(array|string|function)',
autoClose: '(boolean|string)',
boundary: '(string|element)',
reference: '(string|element|object)',
display: 'string',
offset: '(array|string|function)',
popperConfig: '(null|object|function)',
autoClose: '(boolean|string)'
reference: '(string|element|object)'
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
* Class definition
*/
class Dropdown extends BaseComponent__default.default {
class Dropdown extends BaseComponent {
constructor(element, config) {
super(element);
super(element, config);
this._popper = null;
this._config = this._getConfig(config);
this._menu = this._getMenuElement();
this._parent = this._element.parentNode; // dropdown wrapper
// TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU)[0] || SelectorEngine.findOne(SELECTOR_MENU, this._parent);
this._inNavbar = this._detectNavbar();
} // Getters
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
} // Public
}
// Public
toggle() {
return this._isShown() ? this.hide() : this.show();
}
show() {
if (isDisabled(this._element) || this._isShown(this._menu)) {
if (index_js.isDisabled(this._element) || this._isShown()) {
return;
}
const relatedTarget = {
relatedTarget: this._element
};
const showEvent = EventHandler__default.default.trigger(this._element, EVENT_SHOW, relatedTarget);
const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget);
if (showEvent.defaultPrevented) {
return;
}
this._createPopper();
const parent = Dropdown.getParentFromElement(this._element); // Totally disable Popper for Dropdowns in Navbar
if (this._inNavbar) {
Manipulator__default.default.setDataAttribute(this._menu, 'popper', 'none');
} else {
this._createPopper(parent);
} // If this is a touch-enabled device we add extra
// If this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
if ('ontouchstart' in document.documentElement && !parent.closest(SELECTOR_NAVBAR_NAV)) {
[].concat(...document.body.children).forEach(elem => EventHandler__default.default.on(elem, 'mouseover', noop));
if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {
for (const element of [].concat(...document.body.children)) {
EventHandler.on(element, 'mouseover', index_js.noop);
}
}
this._element.focus();
this._element.setAttribute('aria-expanded', true);
this._menu.classList.add(CLASS_NAME_SHOW);
this._element.classList.add(CLASS_NAME_SHOW);
EventHandler__default.default.trigger(this._element, EVENT_SHOWN, relatedTarget);
EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget);
}
hide() {
if (isDisabled(this._element) || !this._isShown(this._menu)) {
if (index_js.isDisabled(this._element) || !this._isShown()) {
return;
}
const relatedTarget = {
relatedTarget: this._element
};
this._completeHide(relatedTarget);
}
dispose() {
if (this._popper) {
this._popper.destroy();
}
super.dispose();
}
update() {
this._inNavbar = this._detectNavbar();
if (this._popper) {
this._popper.update();
}
} // Private
}
// Private
_completeHide(relatedTarget) {
const hideEvent = EventHandler__default.default.trigger(this._element, EVENT_HIDE, relatedTarget);
const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget);
if (hideEvent.defaultPrevented) {
return;
} // If this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
if ('ontouchstart' in document.documentElement) {
[].concat(...document.body.children).forEach(elem => EventHandler__default.default.off(elem, 'mouseover', noop));
}
// If this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
if ('ontouchstart' in document.documentElement) {
for (const element of [].concat(...document.body.children)) {
EventHandler.off(element, 'mouseover', index_js.noop);
}
}
if (this._popper) {
this._popper.destroy();
}
this._menu.classList.remove(CLASS_NAME_SHOW);
this._element.classList.remove(CLASS_NAME_SHOW);
this._element.setAttribute('aria-expanded', 'false');
Manipulator__default.default.removeDataAttribute(this._menu, 'popper');
EventHandler__default.default.trigger(this._element, EVENT_HIDDEN, relatedTarget);
Manipulator.removeDataAttribute(this._menu, 'popper');
EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget);
}
_getConfig(config) {
config = { ...this.constructor.Default,
...Manipulator__default.default.getDataAttributes(this._element),
...config
};
typeCheckConfig(NAME, config, this.constructor.DefaultType);
if (typeof config.reference === 'object' && !isElement(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') {
config = super._getConfig(config);
if (typeof config.reference === 'object' && !index_js.isElement(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') {
// Popper virtual elements require a getBoundingClientRect method
throw new TypeError(`${NAME.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);
}
return config;
}
_createPopper(parent) {
_createPopper() {
if (typeof Popper__namespace === 'undefined') {
throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)');
}
let referenceElement = this._element;
if (this._config.reference === 'parent') {
referenceElement = parent;
} else if (isElement(this._config.reference)) {
referenceElement = getElement(this._config.reference);
referenceElement = this._parent;
} else if (index_js.isElement(this._config.reference)) {
referenceElement = index_js.getElement(this._config.reference);
} else if (typeof this._config.reference === 'object') {
referenceElement = this._config.reference;
}
const popperConfig = this._getPopperConfig();
const isDisplayStatic = popperConfig.modifiers.find(modifier => modifier.name === 'applyStyles' && modifier.enabled === false);
this._popper = Popper__namespace.createPopper(referenceElement, this._menu, popperConfig);
if (isDisplayStatic) {
Manipulator__default.default.setDataAttribute(this._menu, 'popper', 'static');
}
}
_isShown(element = this._element) {
return element.classList.contains(CLASS_NAME_SHOW);
_isShown() {
return this._menu.classList.contains(CLASS_NAME_SHOW);
}
_getMenuElement() {
return SelectorEngine__default.default.next(this._element, SELECTOR_MENU)[0];
}
_getPlacement() {
const parentDropdown = this._element.parentNode;
const parentDropdown = this._parent;
if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {
return PLACEMENT_RIGHT;
}
if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {
return PLACEMENT_LEFT;
} // We need to trim the value because custom properties can also include spaces
}
if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {
return PLACEMENT_TOPCENTER;
}
if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {
return PLACEMENT_BOTTOMCENTER;
}
// We need to trim the value because custom properties can also include spaces
const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end';
if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP;
}
return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM;
}
_detectNavbar() {
return this._element.closest(`.${CLASS_NAME_NAVBAR}`) !== null;
return this._element.closest(SELECTOR_NAVBAR) !== null;
}
_getOffset() {
const {
offset
} = this._config;
if (typeof offset === 'string') {
return offset.split(',').map(val => Number.parseInt(val, 10));
return offset.split(',').map(value => Number.parseInt(value, 10));
}
if (typeof offset === 'function') {
return popperData => offset(popperData, this._element);
}
return offset;
}
_getPopperConfig() {
const defaultBsPopperConfig = {
placement: this._getPlacement(),
@ -515,172 +274,128 @@
offset: this._getOffset()
}
}]
}; // Disable Popper if we have a static display
};
if (this._config.display === 'static') {
// Disable Popper if we have a static display or Dropdown is in Navbar
if (this._inNavbar || this._config.display === 'static') {
Manipulator.setDataAttribute(this._menu, 'popper', 'static'); // TODO: v6 remove
defaultBsPopperConfig.modifiers = [{
name: 'applyStyles',
enabled: false
}];
}
return { ...defaultBsPopperConfig,
...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)
return {
...defaultBsPopperConfig,
...index_js.execute(this._config.popperConfig, [defaultBsPopperConfig])
};
}
_selectMenuItem({
key,
target
}) {
const items = SelectorEngine__default.default.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible);
const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => index_js.isVisible(element));
if (!items.length) {
return;
} // if target isn't included in items (e.g. when expanding the dropdown)
}
// if target isn't included in items (e.g. when expanding the dropdown)
// allow cycling to get the last item in case key equals ARROW_UP_KEY
index_js.getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus();
}
getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus();
} // Static
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Dropdown.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
static clearMenus(event) {
if (event && (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY)) {
if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY) {
return;
}
const toggles = SelectorEngine__default.default.find(SELECTOR_DATA_TOGGLE);
for (let i = 0, len = toggles.length; i < len; i++) {
const context = Dropdown.getInstance(toggles[i]);
const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN);
for (const toggle of openToggles) {
const context = Dropdown.getInstance(toggle);
if (!context || context._config.autoClose === false) {
continue;
}
if (!context._isShown()) {
const composedPath = event.composedPath();
const isMenuTarget = composedPath.includes(context._menu);
if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) {
continue;
}
// Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu
if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY || /input|select|option|textarea|form/i.test(event.target.tagName))) {
continue;
}
const relatedTarget = {
relatedTarget: context._element
};
if (event) {
const composedPath = event.composedPath();
const isMenuTarget = composedPath.includes(context._menu);
if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) {
continue;
} // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu
if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY || /input|select|option|textarea|form/i.test(event.target.tagName))) {
continue;
}
if (event.type === 'click') {
relatedTarget.clickEvent = event;
}
if (event.type === 'click') {
relatedTarget.clickEvent = event;
}
context._completeHide(relatedTarget);
}
}
static getParentFromElement(element) {
return getElementFromSelector(element) || element.parentNode;
}
static dataApiKeydownHandler(event) {
// If not input/textarea:
// - And not a key in REGEXP_KEYDOWN => not a dropdown command
// If input/textarea:
// - If space key => not a dropdown command
// - If key is other than escape
// - If key is not up or down => not a dropdown command
// - If trigger inside the menu => not a dropdown command
if (/input|textarea/i.test(event.target.tagName) ? event.key === SPACE_KEY || event.key !== ESCAPE_KEY && (event.key !== ARROW_DOWN_KEY && event.key !== ARROW_UP_KEY || event.target.closest(SELECTOR_MENU)) : !REGEXP_KEYDOWN.test(event.key)) {
// If not an UP | DOWN | ESCAPE key => not a dropdown command
// If input/textarea && if key is other than ESCAPE => not a dropdown command
const isInput = /input|textarea/i.test(event.target.tagName);
const isEscapeEvent = event.key === ESCAPE_KEY;
const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key);
if (!isUpOrDownEvent && !isEscapeEvent) {
return;
}
const isActive = this.classList.contains(CLASS_NAME_SHOW);
if (!isActive && event.key === ESCAPE_KEY) {
if (isInput && !isEscapeEvent) {
return;
}
event.preventDefault();
event.stopPropagation();
if (isDisabled(this)) {
return;
}
const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine__default.default.prev(this, SELECTOR_DATA_TOGGLE)[0];
// TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] || SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] || SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode);
const instance = Dropdown.getOrCreateInstance(getToggleButton);
if (event.key === ESCAPE_KEY) {
instance.hide();
return;
}
if (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY) {
if (!isActive) {
instance.show();
}
if (isUpOrDownEvent) {
event.stopPropagation();
instance.show();
instance._selectMenuItem(event);
return;
}
if (!isActive || event.key === SPACE_KEY) {
Dropdown.clearMenus();
if (instance._isShown()) {
// else is escape and we check if it is shown
event.stopPropagation();
instance.hide();
getToggleButton.focus();
}
}
}
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
* Data API implementation
*/
EventHandler__default.default.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler);
EventHandler__default.default.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU_NOT_SUB, Dropdown.dataApiKeydownHandler);
EventHandler__default.default.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus);
EventHandler__default.default.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus);
EventHandler__default.default.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler);
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU_NOT_SUB, Dropdown.dataApiKeydownHandler);
EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus);
EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus);
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
event.preventDefault();
Dropdown.getOrCreateInstance(this).toggle();
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .Dropdown to jQuery only if jQuery is present
*/
defineJQueryPlugin(Dropdown);
index_js.defineJQueryPlugin(Dropdown);
return Dropdown;

File diff suppressed because it is too large Load diff

View file

@ -1,620 +1,24 @@
/*!
* Bootstrap offcanvas.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap offcanvas.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/selector-engine.js'), require('./dom/manipulator.js'), require('./dom/event-handler.js'), require('./base-component.js')) :
typeof define === 'function' && define.amd ? define(['./dom/selector-engine', './dom/manipulator', './dom/event-handler', './base-component'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Offcanvas = factory(global.SelectorEngine, global.Manipulator, global.EventHandler, global.Base));
})(this, (function (SelectorEngine, Manipulator, EventHandler, BaseComponent) { 'use strict';
const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
const SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
const Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./dom/selector-engine.js'), require('./util/backdrop.js'), require('./util/component-functions.js'), require('./util/focustrap.js'), require('./util/index.js'), require('./util/scrollbar.js')) :
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './dom/selector-engine', './util/backdrop', './util/component-functions', './util/focustrap', './util/index', './util/scrollbar'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Offcanvas = factory(global.BaseComponent, global.EventHandler, global.SelectorEngine, global.Backdrop, global.ComponentFunctions, global.Focustrap, global.Index, global.Scrollbar));
})(this, (function (BaseComponent, EventHandler, SelectorEngine, Backdrop, componentFunctions_js, FocusTrap, index_js, ScrollBarHelper) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const MILLISECONDS_MULTIPLIER = 1000;
const TRANSITION_END = 'transitionend'; // Shoutout AngusCroll (https://goo.gl/pxwQGp)
const toType = obj => {
if (obj === null || obj === undefined) {
return `${obj}`;
}
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
};
const getSelector = element => {
let selector = element.getAttribute('data-bs-target');
if (!selector || selector === '#') {
let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
// so everything starting with `#` or `.`. If a "real" URL is used as the selector,
// `document.querySelector` will rightfully complain it is invalid.
// See https://github.com/twbs/bootstrap/issues/32273
if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
return null;
} // Just in case some CMS puts out a full URL with the anchor appended
if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
hrefAttr = `#${hrefAttr.split('#')[1]}`;
}
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
}
return selector;
};
const getElementFromSelector = element => {
const selector = getSelector(element);
return selector ? document.querySelector(selector) : null;
};
const getTransitionDurationFromElement = element => {
if (!element) {
return 0;
} // Get transition-duration of the element
let {
transitionDuration,
transitionDelay
} = window.getComputedStyle(element);
const floatTransitionDuration = Number.parseFloat(transitionDuration);
const floatTransitionDelay = Number.parseFloat(transitionDelay); // Return 0 if element or transition duration is not found
if (!floatTransitionDuration && !floatTransitionDelay) {
return 0;
} // If multiple durations are defined, take the first
transitionDuration = transitionDuration.split(',')[0];
transitionDelay = transitionDelay.split(',')[0];
return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;
};
const triggerTransitionEnd = element => {
element.dispatchEvent(new Event(TRANSITION_END));
};
const isElement = obj => {
if (!obj || typeof obj !== 'object') {
return false;
}
if (typeof obj.jquery !== 'undefined') {
obj = obj[0];
}
return typeof obj.nodeType !== 'undefined';
};
const getElement = obj => {
if (isElement(obj)) {
// it's a jQuery object or a node element
return obj.jquery ? obj[0] : obj;
}
if (typeof obj === 'string' && obj.length > 0) {
return document.querySelector(obj);
}
return null;
};
const typeCheckConfig = (componentName, config, configTypes) => {
Object.keys(configTypes).forEach(property => {
const expectedTypes = configTypes[property];
const value = config[property];
const valueType = value && isElement(value) ? 'element' : toType(value);
if (!new RegExp(expectedTypes).test(valueType)) {
throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
}
});
};
const isVisible = element => {
if (!isElement(element) || element.getClientRects().length === 0) {
return false;
}
return getComputedStyle(element).getPropertyValue('visibility') === 'visible';
};
const isDisabled = element => {
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
return true;
}
if (element.classList.contains('disabled')) {
return true;
}
if (typeof element.disabled !== 'undefined') {
return element.disabled;
}
return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
};
/**
* Trick to restart an element's animation
*
* @param {HTMLElement} element
* @return void
*
* @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
*/
const reflow = element => {
// eslint-disable-next-line no-unused-expressions
element.offsetHeight;
};
const getjQuery = () => {
const {
jQuery
} = window;
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
return jQuery;
}
return null;
};
const DOMContentLoadedCallbacks = [];
const onDOMContentLoaded = callback => {
if (document.readyState === 'loading') {
// add listener on the first call when the document is in loading state
if (!DOMContentLoadedCallbacks.length) {
document.addEventListener('DOMContentLoaded', () => {
DOMContentLoadedCallbacks.forEach(callback => callback());
});
}
DOMContentLoadedCallbacks.push(callback);
} else {
callback();
}
};
const defineJQueryPlugin = plugin => {
onDOMContentLoaded(() => {
const $ = getjQuery();
/* istanbul ignore if */
if ($) {
const name = plugin.NAME;
const JQUERY_NO_CONFLICT = $.fn[name];
$.fn[name] = plugin.jQueryInterface;
$.fn[name].Constructor = plugin;
$.fn[name].noConflict = () => {
$.fn[name] = JQUERY_NO_CONFLICT;
return plugin.jQueryInterface;
};
}
});
};
const execute = callback => {
if (typeof callback === 'function') {
callback();
}
};
const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
if (!waitForTransition) {
execute(callback);
return;
}
const durationPadding = 5;
const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;
let called = false;
const handler = ({
target
}) => {
if (target !== transitionElement) {
return;
}
called = true;
transitionElement.removeEventListener(TRANSITION_END, handler);
execute(callback);
};
transitionElement.addEventListener(TRANSITION_END, handler);
setTimeout(() => {
if (!called) {
triggerTransitionEnd(transitionElement);
}
}, emulatedDuration);
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/scrollBar.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
const SELECTOR_STICKY_CONTENT = '.sticky-top';
class ScrollBarHelper {
constructor() {
this._element = document.body;
}
getWidth() {
// https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
const documentWidth = document.documentElement.clientWidth;
return Math.abs(window.innerWidth - documentWidth);
}
hide() {
const width = this.getWidth();
this._disableOverFlow(); // give padding to element to balance the hidden scrollbar width
this._setElementAttributes(this._element, 'paddingRight', calculatedValue => calculatedValue + width); // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
this._setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width);
this._setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width);
}
_disableOverFlow() {
this._saveInitialAttribute(this._element, 'overflow');
this._element.style.overflow = 'hidden';
}
_setElementAttributes(selector, styleProp, callback) {
const scrollbarWidth = this.getWidth();
const manipulationCallBack = element => {
if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
return;
}
this._saveInitialAttribute(element, styleProp);
const calculatedValue = window.getComputedStyle(element)[styleProp];
element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px`;
};
this._applyManipulationCallback(selector, manipulationCallBack);
}
reset() {
this._resetElementAttributes(this._element, 'overflow');
this._resetElementAttributes(this._element, 'paddingRight');
this._resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight');
this._resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight');
}
_saveInitialAttribute(element, styleProp) {
const actualValue = element.style[styleProp];
if (actualValue) {
Manipulator__default.default.setDataAttribute(element, styleProp, actualValue);
}
}
_resetElementAttributes(selector, styleProp) {
const manipulationCallBack = element => {
const value = Manipulator__default.default.getDataAttribute(element, styleProp);
if (typeof value === 'undefined') {
element.style.removeProperty(styleProp);
} else {
Manipulator__default.default.removeDataAttribute(element, styleProp);
element.style[styleProp] = value;
}
};
this._applyManipulationCallback(selector, manipulationCallBack);
}
_applyManipulationCallback(selector, callBack) {
if (isElement(selector)) {
callBack(selector);
} else {
SelectorEngine__default.default.find(selector, this._element).forEach(callBack);
}
}
isOverflowing() {
return this.getWidth() > 0;
}
}
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/backdrop.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const Default$2 = {
className: 'modal-backdrop',
isVisible: true,
// if false, we use the backdrop helper without adding any element to the dom
isAnimated: false,
rootElement: 'body',
// give the choice to place backdrop under different elements
clickCallback: null
};
const DefaultType$2 = {
className: 'string',
isVisible: 'boolean',
isAnimated: 'boolean',
rootElement: '(element|string)',
clickCallback: '(function|null)'
};
const NAME$2 = 'backdrop';
const CLASS_NAME_FADE = 'fade';
const CLASS_NAME_SHOW$1 = 'show';
const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$2}`;
class Backdrop {
constructor(config) {
this._config = this._getConfig(config);
this._isAppended = false;
this._element = null;
}
show(callback) {
if (!this._config.isVisible) {
execute(callback);
return;
}
this._append();
if (this._config.isAnimated) {
reflow(this._getElement());
}
this._getElement().classList.add(CLASS_NAME_SHOW$1);
this._emulateAnimation(() => {
execute(callback);
});
}
hide(callback) {
if (!this._config.isVisible) {
execute(callback);
return;
}
this._getElement().classList.remove(CLASS_NAME_SHOW$1);
this._emulateAnimation(() => {
this.dispose();
execute(callback);
});
} // Private
_getElement() {
if (!this._element) {
const backdrop = document.createElement('div');
backdrop.className = this._config.className;
if (this._config.isAnimated) {
backdrop.classList.add(CLASS_NAME_FADE);
}
this._element = backdrop;
}
return this._element;
}
_getConfig(config) {
config = { ...Default$2,
...(typeof config === 'object' ? config : {})
}; // use getElement() with the default "body" to get a fresh Element on each instantiation
config.rootElement = getElement(config.rootElement);
typeCheckConfig(NAME$2, config, DefaultType$2);
return config;
}
_append() {
if (this._isAppended) {
return;
}
this._config.rootElement.append(this._getElement());
EventHandler__default.default.on(this._getElement(), EVENT_MOUSEDOWN, () => {
execute(this._config.clickCallback);
});
this._isAppended = true;
}
dispose() {
if (!this._isAppended) {
return;
}
EventHandler__default.default.off(this._element, EVENT_MOUSEDOWN);
this._element.remove();
this._isAppended = false;
}
_emulateAnimation(callback) {
executeAfterTransition(callback, this._getElement(), this._config.isAnimated);
}
}
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/focustrap.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const Default$1 = {
trapElement: null,
// The element to trap focus inside of
autofocus: true
};
const DefaultType$1 = {
trapElement: 'element',
autofocus: 'boolean'
};
const NAME$1 = 'focustrap';
const DATA_KEY$1 = 'bs.focustrap';
const EVENT_KEY$1 = `.${DATA_KEY$1}`;
const EVENT_FOCUSIN = `focusin${EVENT_KEY$1}`;
const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$1}`;
const TAB_KEY = 'Tab';
const TAB_NAV_FORWARD = 'forward';
const TAB_NAV_BACKWARD = 'backward';
class FocusTrap {
constructor(config) {
this._config = this._getConfig(config);
this._isActive = false;
this._lastTabNavDirection = null;
}
activate() {
const {
trapElement,
autofocus
} = this._config;
if (this._isActive) {
return;
}
if (autofocus) {
trapElement.focus();
}
EventHandler__default.default.off(document, EVENT_KEY$1); // guard against infinite focus loop
EventHandler__default.default.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event));
EventHandler__default.default.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));
this._isActive = true;
}
deactivate() {
if (!this._isActive) {
return;
}
this._isActive = false;
EventHandler__default.default.off(document, EVENT_KEY$1);
} // Private
_handleFocusin(event) {
const {
target
} = event;
const {
trapElement
} = this._config;
if (target === document || target === trapElement || trapElement.contains(target)) {
return;
}
const elements = SelectorEngine__default.default.focusableChildren(trapElement);
if (elements.length === 0) {
trapElement.focus();
} else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
elements[elements.length - 1].focus();
} else {
elements[0].focus();
}
}
_handleKeydown(event) {
if (event.key !== TAB_KEY) {
return;
}
this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;
}
_getConfig(config) {
config = { ...Default$1,
...(typeof config === 'object' ? config : {})
};
typeCheckConfig(NAME$1, config, DefaultType$1);
return config;
}
}
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/component-functions.js
* Bootstrap offcanvas.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const enableDismissTrigger = (component, method = 'hide') => {
const clickEvent = `click.dismiss${component.EVENT_KEY}`;
const name = component.NAME;
EventHandler__default.default.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault();
}
if (isDisabled(this)) {
return;
}
const target = getElementFromSelector(this) || this.closest(`.${name}`);
const instance = component.getOrCreateInstance(target); // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
instance[method]();
});
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): offcanvas.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'offcanvas';
@ -623,243 +27,218 @@
const DATA_API_KEY = '.data-api';
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`;
const ESCAPE_KEY = 'Escape';
const CLASS_NAME_SHOW = 'show';
const CLASS_NAME_SHOWING = 'showing';
const CLASS_NAME_HIDING = 'hiding';
const CLASS_NAME_BACKDROP = 'offcanvas-backdrop';
const OPEN_SELECTOR = '.offcanvas.show';
const EVENT_SHOW = `show${EVENT_KEY}`;
const EVENT_SHOWN = `shown${EVENT_KEY}`;
const EVENT_HIDE = `hide${EVENT_KEY}`;
const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`;
const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
const EVENT_RESIZE = `resize${EVENT_KEY}`;
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`;
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="offcanvas"]';
const Default = {
backdrop: true,
keyboard: true,
scroll: false
};
const DefaultType = {
backdrop: 'boolean',
backdrop: '(boolean|string)',
keyboard: 'boolean',
scroll: 'boolean'
};
const CLASS_NAME_SHOW = 'show';
const CLASS_NAME_BACKDROP = 'offcanvas-backdrop';
const OPEN_SELECTOR = '.offcanvas.show';
const EVENT_SHOW = `show${EVENT_KEY}`;
const EVENT_SHOWN = `shown${EVENT_KEY}`;
const EVENT_HIDE = `hide${EVENT_KEY}`;
const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`;
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="offcanvas"]';
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
* Class definition
*/
class Offcanvas extends BaseComponent__default.default {
class Offcanvas extends BaseComponent {
constructor(element, config) {
super(element);
this._config = this._getConfig(config);
super(element, config);
this._isShown = false;
this._backdrop = this._initializeBackDrop();
this._focustrap = this._initializeFocusTrap();
this._addEventListeners();
} // Getters
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
}
static get Default() {
return Default;
} // Public
// Public
toggle(relatedTarget) {
return this._isShown ? this.hide() : this.show(relatedTarget);
}
show(relatedTarget) {
if (this._isShown) {
return;
}
const showEvent = EventHandler__default.default.trigger(this._element, EVENT_SHOW, {
const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {
relatedTarget
});
if (showEvent.defaultPrevented) {
return;
}
this._isShown = true;
this._element.style.visibility = 'visible';
this._backdrop.show();
if (!this._config.scroll) {
new ScrollBarHelper().hide();
}
this._element.removeAttribute('aria-hidden');
this._element.setAttribute('aria-modal', true);
this._element.setAttribute('role', 'dialog');
this._element.classList.add(CLASS_NAME_SHOW);
this._element.classList.add(CLASS_NAME_SHOWING);
const completeCallBack = () => {
if (!this._config.scroll) {
if (!this._config.scroll || this._config.backdrop) {
this._focustrap.activate();
}
EventHandler__default.default.trigger(this._element, EVENT_SHOWN, {
this._element.classList.add(CLASS_NAME_SHOW);
this._element.classList.remove(CLASS_NAME_SHOWING);
EventHandler.trigger(this._element, EVENT_SHOWN, {
relatedTarget
});
};
this._queueCallback(completeCallBack, this._element, true);
}
hide() {
if (!this._isShown) {
return;
}
const hideEvent = EventHandler__default.default.trigger(this._element, EVENT_HIDE);
const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE);
if (hideEvent.defaultPrevented) {
return;
}
this._focustrap.deactivate();
this._element.blur();
this._isShown = false;
this._element.classList.remove(CLASS_NAME_SHOW);
this._element.classList.add(CLASS_NAME_HIDING);
this._backdrop.hide();
const completeCallback = () => {
this._element.setAttribute('aria-hidden', true);
this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING);
this._element.removeAttribute('aria-modal');
this._element.removeAttribute('role');
this._element.style.visibility = 'hidden';
if (!this._config.scroll) {
new ScrollBarHelper().reset();
}
EventHandler__default.default.trigger(this._element, EVENT_HIDDEN);
EventHandler.trigger(this._element, EVENT_HIDDEN);
};
this._queueCallback(completeCallback, this._element, true);
}
dispose() {
this._backdrop.dispose();
this._focustrap.deactivate();
super.dispose();
} // Private
_getConfig(config) {
config = { ...Default,
...Manipulator__default.default.getDataAttributes(this._element),
...(typeof config === 'object' ? config : {})
};
typeCheckConfig(NAME, config, DefaultType);
return config;
}
// Private
_initializeBackDrop() {
const clickCallback = () => {
if (this._config.backdrop === 'static') {
EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);
return;
}
this.hide();
};
// 'static' option will be translated to true, and booleans will keep their value
const isVisible = Boolean(this._config.backdrop);
return new Backdrop({
className: CLASS_NAME_BACKDROP,
isVisible: this._config.backdrop,
isVisible,
isAnimated: true,
rootElement: this._element.parentNode,
clickCallback: () => this.hide()
clickCallback: isVisible ? clickCallback : null
});
}
_initializeFocusTrap() {
return new FocusTrap({
trapElement: this._element
});
}
_addEventListeners() {
EventHandler__default.default.on(this._element, EVENT_KEYDOWN_DISMISS, event => {
if (this._config.keyboard && event.key === ESCAPE_KEY) {
this.hide();
EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {
if (event.key !== ESCAPE_KEY) {
return;
}
if (this._config.keyboard) {
this.hide();
return;
}
EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);
});
} // Static
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Offcanvas.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`);
}
data[config](this);
});
}
}
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
* Data API implementation
*/
EventHandler__default.default.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
const target = getElementFromSelector(this);
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
const target = SelectorEngine.getElementFromSelector(this);
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault();
}
if (isDisabled(this)) {
if (index_js.isDisabled(this)) {
return;
}
EventHandler__default.default.one(target, EVENT_HIDDEN, () => {
EventHandler.one(target, EVENT_HIDDEN, () => {
// focus on trigger when it is closed
if (isVisible(this)) {
if (index_js.isVisible(this)) {
this.focus();
}
}); // avoid conflict when clicking a toggler of an offcanvas, while another is open
});
const allReadyOpen = SelectorEngine__default.default.findOne(OPEN_SELECTOR);
if (allReadyOpen && allReadyOpen !== target) {
Offcanvas.getInstance(allReadyOpen).hide();
// avoid conflict when clicking a toggler of an offcanvas, while another is open
const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR);
if (alreadyOpen && alreadyOpen !== target) {
Offcanvas.getInstance(alreadyOpen).hide();
}
const data = Offcanvas.getOrCreateInstance(target);
data.toggle(this);
});
EventHandler__default.default.on(window, EVENT_LOAD_DATA_API, () => SelectorEngine__default.default.find(OPEN_SELECTOR).forEach(el => Offcanvas.getOrCreateInstance(el).show()));
enableDismissTrigger(Offcanvas);
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {
Offcanvas.getOrCreateInstance(selector).show();
}
});
EventHandler.on(window, EVENT_RESIZE, () => {
for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {
if (getComputedStyle(element).position !== 'fixed') {
Offcanvas.getOrCreateInstance(element).hide();
}
}
});
componentFunctions_js.enableDismissTrigger(Offcanvas);
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
defineJQueryPlugin(Offcanvas);
index_js.defineJQueryPlugin(Offcanvas);
return Offcanvas;

View file

@ -1,182 +1,94 @@
/*!
* Bootstrap popover.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap popover.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./tooltip.js')) :
typeof define === 'function' && define.amd ? define(['./tooltip'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Popover = factory(global.Tooltip));
})(this, (function (Tooltip) { 'use strict';
const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
const Tooltip__default = /*#__PURE__*/_interopDefaultLegacy(Tooltip);
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./tooltip.js'), require('./util/index.js')) :
typeof define === 'function' && define.amd ? define(['./tooltip', './util/index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Popover = factory(global.Tooltip, global.Index));
})(this, (function (Tooltip, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Bootstrap popover.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const getjQuery = () => {
const {
jQuery
} = window;
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
return jQuery;
}
return null;
};
const DOMContentLoadedCallbacks = [];
const onDOMContentLoaded = callback => {
if (document.readyState === 'loading') {
// add listener on the first call when the document is in loading state
if (!DOMContentLoadedCallbacks.length) {
document.addEventListener('DOMContentLoaded', () => {
DOMContentLoadedCallbacks.forEach(callback => callback());
});
}
DOMContentLoadedCallbacks.push(callback);
} else {
callback();
}
};
const defineJQueryPlugin = plugin => {
onDOMContentLoaded(() => {
const $ = getjQuery();
/* istanbul ignore if */
if ($) {
const name = plugin.NAME;
const JQUERY_NO_CONFLICT = $.fn[name];
$.fn[name] = plugin.jQueryInterface;
$.fn[name].Constructor = plugin;
$.fn[name].noConflict = () => {
$.fn[name] = JQUERY_NO_CONFLICT;
return plugin.jQueryInterface;
};
}
});
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): popover.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'popover';
const DATA_KEY = 'bs.popover';
const EVENT_KEY = `.${DATA_KEY}`;
const CLASS_PREFIX = 'bs-popover';
const Default = { ...Tooltip__default.default.Default,
placement: 'right',
offset: [0, 8],
trigger: 'click',
content: '',
template: '<div class="popover" role="tooltip">' + '<div class="popover-arrow"></div>' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div>' + '</div>'
};
const DefaultType = { ...Tooltip__default.default.DefaultType,
content: '(string|element|function)'
};
const Event = {
HIDE: `hide${EVENT_KEY}`,
HIDDEN: `hidden${EVENT_KEY}`,
SHOW: `show${EVENT_KEY}`,
SHOWN: `shown${EVENT_KEY}`,
INSERTED: `inserted${EVENT_KEY}`,
CLICK: `click${EVENT_KEY}`,
FOCUSIN: `focusin${EVENT_KEY}`,
FOCUSOUT: `focusout${EVENT_KEY}`,
MOUSEENTER: `mouseenter${EVENT_KEY}`,
MOUSELEAVE: `mouseleave${EVENT_KEY}`
};
const SELECTOR_TITLE = '.popover-header';
const SELECTOR_CONTENT = '.popover-body';
const Default = {
...Tooltip.Default,
content: '',
offset: [0, 8],
placement: 'right',
template: '<div class="popover" role="tooltip">' + '<div class="popover-arrow"></div>' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div>' + '</div>',
trigger: 'click'
};
const DefaultType = {
...Tooltip.DefaultType,
content: '(null|string|element|function)'
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
* Class definition
*/
class Popover extends Tooltip__default.default {
class Popover extends Tooltip {
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
}
static get Event() {
return Event;
// Overrides
_isWithContent() {
return this._getTitle() || this._getContent();
}
static get DefaultType() {
return DefaultType;
} // Overrides
isWithContent() {
return this.getTitle() || this._getContent();
// Private
_getContentForTemplate() {
return {
[SELECTOR_TITLE]: this._getTitle(),
[SELECTOR_CONTENT]: this._getContent()
};
}
setContent(tip) {
this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TITLE);
this._sanitizeAndSetContent(tip, this._getContent(), SELECTOR_CONTENT);
} // Private
_getContent() {
return this._resolvePossibleFunction(this._config.content);
}
_getBasicClassPrefix() {
return CLASS_PREFIX;
} // Static
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Popover.getOrCreateInstance(this, config);
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .Popover to jQuery only if jQuery is present
*/
defineJQueryPlugin(Popover);
index_js.defineJQueryPlugin(Popover);
return Popover;

View file

@ -1,389 +1,273 @@
/*!
* Bootstrap scrollspy.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap scrollspy.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./base-component.js')) :
typeof define === 'function' && define.amd ? define(['./dom/event-handler', './dom/manipulator', './dom/selector-engine', './base-component'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ScrollSpy = factory(global.EventHandler, global.Manipulator, global.SelectorEngine, global.Base));
})(this, (function (EventHandler, Manipulator, SelectorEngine, BaseComponent) { 'use strict';
const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
const Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
const SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./dom/selector-engine.js'), require('./util/index.js')) :
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './dom/selector-engine', './util/index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ScrollSpy = factory(global.BaseComponent, global.EventHandler, global.SelectorEngine, global.Index));
})(this, (function (BaseComponent, EventHandler, SelectorEngine, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Bootstrap scrollspy.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const toType = obj => {
if (obj === null || obj === undefined) {
return `${obj}`;
}
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
};
const getSelector = element => {
let selector = element.getAttribute('data-bs-target');
if (!selector || selector === '#') {
let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
// so everything starting with `#` or `.`. If a "real" URL is used as the selector,
// `document.querySelector` will rightfully complain it is invalid.
// See https://github.com/twbs/bootstrap/issues/32273
if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
return null;
} // Just in case some CMS puts out a full URL with the anchor appended
if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
hrefAttr = `#${hrefAttr.split('#')[1]}`;
}
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
}
return selector;
};
const getSelectorFromElement = element => {
const selector = getSelector(element);
if (selector) {
return document.querySelector(selector) ? selector : null;
}
return null;
};
const isElement = obj => {
if (!obj || typeof obj !== 'object') {
return false;
}
if (typeof obj.jquery !== 'undefined') {
obj = obj[0];
}
return typeof obj.nodeType !== 'undefined';
};
const getElement = obj => {
if (isElement(obj)) {
// it's a jQuery object or a node element
return obj.jquery ? obj[0] : obj;
}
if (typeof obj === 'string' && obj.length > 0) {
return document.querySelector(obj);
}
return null;
};
const typeCheckConfig = (componentName, config, configTypes) => {
Object.keys(configTypes).forEach(property => {
const expectedTypes = configTypes[property];
const value = config[property];
const valueType = value && isElement(value) ? 'element' : toType(value);
if (!new RegExp(expectedTypes).test(valueType)) {
throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
}
});
};
const getjQuery = () => {
const {
jQuery
} = window;
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
return jQuery;
}
return null;
};
const DOMContentLoadedCallbacks = [];
const onDOMContentLoaded = callback => {
if (document.readyState === 'loading') {
// add listener on the first call when the document is in loading state
if (!DOMContentLoadedCallbacks.length) {
document.addEventListener('DOMContentLoaded', () => {
DOMContentLoadedCallbacks.forEach(callback => callback());
});
}
DOMContentLoadedCallbacks.push(callback);
} else {
callback();
}
};
const defineJQueryPlugin = plugin => {
onDOMContentLoaded(() => {
const $ = getjQuery();
/* istanbul ignore if */
if ($) {
const name = plugin.NAME;
const JQUERY_NO_CONFLICT = $.fn[name];
$.fn[name] = plugin.jQueryInterface;
$.fn[name].Constructor = plugin;
$.fn[name].noConflict = () => {
$.fn[name] = JQUERY_NO_CONFLICT;
return plugin.jQueryInterface;
};
}
});
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): scrollspy.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'scrollspy';
const DATA_KEY = 'bs.scrollspy';
const EVENT_KEY = `.${DATA_KEY}`;
const DATA_API_KEY = '.data-api';
const Default = {
offset: 10,
method: 'auto',
target: ''
};
const DefaultType = {
offset: 'number',
method: 'string',
target: '(string|element)'
};
const EVENT_ACTIVATE = `activate${EVENT_KEY}`;
const EVENT_SCROLL = `scroll${EVENT_KEY}`;
const EVENT_CLICK = `click${EVENT_KEY}`;
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`;
const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';
const CLASS_NAME_ACTIVE = 'active';
const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]';
const SELECTOR_TARGET_LINKS = '[href]';
const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';
const SELECTOR_NAV_LINKS = '.nav-link';
const SELECTOR_NAV_ITEMS = '.nav-item';
const SELECTOR_LIST_ITEMS = '.list-group-item';
const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}, .${CLASS_NAME_DROPDOWN_ITEM}`;
const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`;
const SELECTOR_DROPDOWN = '.dropdown';
const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
const METHOD_OFFSET = 'offset';
const METHOD_POSITION = 'position';
const Default = {
offset: null,
// TODO: v6 @deprecated, keep it for backwards compatibility reasons
rootMargin: '0px 0px -25%',
smoothScroll: false,
target: null,
threshold: [0.1, 0.5, 1]
};
const DefaultType = {
offset: '(number|null)',
// TODO v6 @deprecated, keep it for backwards compatibility reasons
rootMargin: 'string',
smoothScroll: 'boolean',
target: 'element',
threshold: 'array'
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
* Class definition
*/
class ScrollSpy extends BaseComponent__default.default {
class ScrollSpy extends BaseComponent {
constructor(element, config) {
super(element);
this._scrollElement = this._element.tagName === 'BODY' ? window : this._element;
this._config = this._getConfig(config);
this._offsets = [];
this._targets = [];
super(element, config);
// this._element is the observablesContainer and config.target the menu links wrapper
this._targetLinks = new Map();
this._observableSections = new Map();
this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element;
this._activeTarget = null;
this._scrollHeight = 0;
EventHandler__default.default.on(this._scrollElement, EVENT_SCROLL, () => this._process());
this.refresh();
this._process();
} // Getters
this._observer = null;
this._previousScrollData = {
visibleEntryTop: 0,
parentScrollTop: 0
};
this.refresh(); // initialize
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
} // Public
refresh() {
const autoMethod = this._scrollElement === this._scrollElement.window ? METHOD_OFFSET : METHOD_POSITION;
const offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;
const offsetBase = offsetMethod === METHOD_POSITION ? this._getScrollTop() : 0;
this._offsets = [];
this._targets = [];
this._scrollHeight = this._getScrollHeight();
const targets = SelectorEngine__default.default.find(SELECTOR_LINK_ITEMS, this._config.target);
targets.map(element => {
const targetSelector = getSelectorFromElement(element);
const target = targetSelector ? SelectorEngine__default.default.findOne(targetSelector) : null;
if (target) {
const targetBCR = target.getBoundingClientRect();
if (targetBCR.width || targetBCR.height) {
return [Manipulator__default.default[offsetMethod](target).top + offsetBase, targetSelector];
}
}
return null;
}).filter(item => item).sort((a, b) => a[0] - b[0]).forEach(item => {
this._offsets.push(item[0]);
this._targets.push(item[1]);
});
}
// Public
refresh() {
this._initializeTargetsAndObservables();
this._maybeEnableSmoothScroll();
if (this._observer) {
this._observer.disconnect();
} else {
this._observer = this._getNewObserver();
}
for (const section of this._observableSections.values()) {
this._observer.observe(section);
}
}
dispose() {
EventHandler__default.default.off(this._scrollElement, EVENT_KEY);
this._observer.disconnect();
super.dispose();
} // Private
}
// Private
_configAfterMerge(config) {
// TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case
config.target = index_js.getElement(config.target) || document.body;
_getConfig(config) {
config = { ...Default,
...Manipulator__default.default.getDataAttributes(this._element),
...(typeof config === 'object' && config ? config : {})
};
config.target = getElement(config.target) || document.documentElement;
typeCheckConfig(NAME, config, DefaultType);
// TODO: v6 Only for backwards compatibility reasons. Use rootMargin only
config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin;
if (typeof config.threshold === 'string') {
config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value));
}
return config;
}
_getScrollTop() {
return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;
}
_getScrollHeight() {
return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
}
_getOffsetHeight() {
return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;
}
_process() {
const scrollTop = this._getScrollTop() + this._config.offset;
const scrollHeight = this._getScrollHeight();
const maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();
if (this._scrollHeight !== scrollHeight) {
this.refresh();
}
if (scrollTop >= maxScroll) {
const target = this._targets[this._targets.length - 1];
if (this._activeTarget !== target) {
this._activate(target);
}
_maybeEnableSmoothScroll() {
if (!this._config.smoothScroll) {
return;
}
if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {
this._activeTarget = null;
// unregister any previous listeners
EventHandler.off(this._config.target, EVENT_CLICK);
EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {
const observableSection = this._observableSections.get(event.target.hash);
if (observableSection) {
event.preventDefault();
const root = this._rootElement || window;
const height = observableSection.offsetTop - this._element.offsetTop;
if (root.scrollTo) {
root.scrollTo({
top: height,
behavior: 'smooth'
});
return;
}
this._clear();
// Chrome 60 doesn't support `scrollTo`
root.scrollTop = height;
}
});
}
_getNewObserver() {
const options = {
root: this._rootElement,
threshold: this._config.threshold,
rootMargin: this._config.rootMargin
};
return new IntersectionObserver(entries => this._observerCallback(entries), options);
}
return;
}
// The logic of selection
_observerCallback(entries) {
const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`);
const activate = entry => {
this._previousScrollData.visibleEntryTop = entry.target.offsetTop;
this._process(targetElement(entry));
};
const parentScrollTop = (this._rootElement || document.documentElement).scrollTop;
const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop;
this._previousScrollData.parentScrollTop = parentScrollTop;
for (const entry of entries) {
if (!entry.isIntersecting) {
this._activeTarget = null;
this._clearActiveClass(targetElement(entry));
continue;
}
const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop;
// if we are scrolling down, pick the bigger offsetTop
if (userScrollsDown && entryIsLowerThanPrevious) {
activate(entry);
// if parent isn't scrolled, let's keep the first visible item, breaking the iteration
if (!parentScrollTop) {
return;
}
continue;
}
for (let i = this._offsets.length; i--;) {
const isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);
if (isActiveTarget) {
this._activate(this._targets[i]);
// if we are scrolling up, pick the smallest offsetTop
if (!userScrollsDown && !entryIsLowerThanPrevious) {
activate(entry);
}
}
}
_initializeTargetsAndObservables() {
this._targetLinks = new Map();
this._observableSections = new Map();
const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target);
for (const anchor of targetLinks) {
// ensure that the anchor has an id and is not disabled
if (!anchor.hash || index_js.isDisabled(anchor)) {
continue;
}
const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element);
_activate(target) {
// ensure that the observableSection exists & is visible
if (index_js.isVisible(observableSection)) {
this._targetLinks.set(decodeURI(anchor.hash), anchor);
this._observableSections.set(anchor.hash, observableSection);
}
}
}
_process(target) {
if (this._activeTarget === target) {
return;
}
this._clearActiveClass(this._config.target);
this._activeTarget = target;
this._clear();
const queries = SELECTOR_LINK_ITEMS.split(',').map(selector => `${selector}[data-bs-target="${target}"],${selector}[href="${target}"]`);
const link = SelectorEngine__default.default.findOne(queries.join(','), this._config.target);
link.classList.add(CLASS_NAME_ACTIVE);
if (link.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {
SelectorEngine__default.default.findOne(SELECTOR_DROPDOWN_TOGGLE, link.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE);
} else {
SelectorEngine__default.default.parents(link, SELECTOR_NAV_LIST_GROUP).forEach(listGroup => {
// Set triggered links parents as active
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
SelectorEngine__default.default.prev(listGroup, `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`).forEach(item => item.classList.add(CLASS_NAME_ACTIVE)); // Handle special case when .nav-link is inside .nav-item
SelectorEngine__default.default.prev(listGroup, SELECTOR_NAV_ITEMS).forEach(navItem => {
SelectorEngine__default.default.children(navItem, SELECTOR_NAV_LINKS).forEach(item => item.classList.add(CLASS_NAME_ACTIVE));
});
});
}
EventHandler__default.default.trigger(this._scrollElement, EVENT_ACTIVATE, {
target.classList.add(CLASS_NAME_ACTIVE);
this._activateParents(target);
EventHandler.trigger(this._element, EVENT_ACTIVATE, {
relatedTarget: target
});
}
_activateParents(target) {
// Activate dropdown parents
if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {
SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE);
return;
}
for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {
// Set triggered links parents as active
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {
item.classList.add(CLASS_NAME_ACTIVE);
}
}
}
_clearActiveClass(parent) {
parent.classList.remove(CLASS_NAME_ACTIVE);
const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent);
for (const node of activeNodes) {
node.classList.remove(CLASS_NAME_ACTIVE);
}
}
_clear() {
SelectorEngine__default.default.find(SELECTOR_LINK_ITEMS, this._config.target).filter(node => node.classList.contains(CLASS_NAME_ACTIVE)).forEach(node => node.classList.remove(CLASS_NAME_ACTIVE));
} // Static
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = ScrollSpy.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
* Data API implementation
*/
EventHandler__default.default.on(window, EVENT_LOAD_DATA_API, () => {
SelectorEngine__default.default.find(SELECTOR_DATA_SPY).forEach(spy => new ScrollSpy(spy));
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {
ScrollSpy.getOrCreateInstance(spy);
}
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .ScrollSpy to jQuery only if jQuery is present
*/
defineJQueryPlugin(ScrollSpy);
index_js.defineJQueryPlugin(ScrollSpy);
return ScrollSpy;

View file

@ -1,331 +1,283 @@
/*!
* Bootstrap tab.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap tab.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/event-handler.js'), require('./dom/selector-engine.js'), require('./base-component.js')) :
typeof define === 'function' && define.amd ? define(['./dom/event-handler', './dom/selector-engine', './base-component'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Tab = factory(global.EventHandler, global.SelectorEngine, global.Base));
})(this, (function (EventHandler, SelectorEngine, BaseComponent) { 'use strict';
const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
const SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./dom/selector-engine.js'), require('./util/index.js')) :
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './dom/selector-engine', './util/index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Tab = factory(global.BaseComponent, global.EventHandler, global.SelectorEngine, global.Index));
})(this, (function (BaseComponent, EventHandler, SelectorEngine, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Bootstrap tab.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const getSelector = element => {
let selector = element.getAttribute('data-bs-target');
if (!selector || selector === '#') {
let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
// so everything starting with `#` or `.`. If a "real" URL is used as the selector,
// `document.querySelector` will rightfully complain it is invalid.
// See https://github.com/twbs/bootstrap/issues/32273
if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
return null;
} // Just in case some CMS puts out a full URL with the anchor appended
if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
hrefAttr = `#${hrefAttr.split('#')[1]}`;
}
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
}
return selector;
};
const getElementFromSelector = element => {
const selector = getSelector(element);
return selector ? document.querySelector(selector) : null;
};
const isDisabled = element => {
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
return true;
}
if (element.classList.contains('disabled')) {
return true;
}
if (typeof element.disabled !== 'undefined') {
return element.disabled;
}
return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
};
/**
* Trick to restart an element's animation
*
* @param {HTMLElement} element
* @return void
*
* @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
*/
const reflow = element => {
// eslint-disable-next-line no-unused-expressions
element.offsetHeight;
};
const getjQuery = () => {
const {
jQuery
} = window;
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
return jQuery;
}
return null;
};
const DOMContentLoadedCallbacks = [];
const onDOMContentLoaded = callback => {
if (document.readyState === 'loading') {
// add listener on the first call when the document is in loading state
if (!DOMContentLoadedCallbacks.length) {
document.addEventListener('DOMContentLoaded', () => {
DOMContentLoadedCallbacks.forEach(callback => callback());
});
}
DOMContentLoadedCallbacks.push(callback);
} else {
callback();
}
};
const defineJQueryPlugin = plugin => {
onDOMContentLoaded(() => {
const $ = getjQuery();
/* istanbul ignore if */
if ($) {
const name = plugin.NAME;
const JQUERY_NO_CONFLICT = $.fn[name];
$.fn[name] = plugin.jQueryInterface;
$.fn[name].Constructor = plugin;
$.fn[name].noConflict = () => {
$.fn[name] = JQUERY_NO_CONFLICT;
return plugin.jQueryInterface;
};
}
});
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): tab.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'tab';
const DATA_KEY = 'bs.tab';
const EVENT_KEY = `.${DATA_KEY}`;
const DATA_API_KEY = '.data-api';
const EVENT_HIDE = `hide${EVENT_KEY}`;
const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
const EVENT_SHOW = `show${EVENT_KEY}`;
const EVENT_SHOWN = `shown${EVENT_KEY}`;
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
const CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu';
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}`;
const EVENT_KEYDOWN = `keydown${EVENT_KEY}`;
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}`;
const ARROW_LEFT_KEY = 'ArrowLeft';
const ARROW_RIGHT_KEY = 'ArrowRight';
const ARROW_UP_KEY = 'ArrowUp';
const ARROW_DOWN_KEY = 'ArrowDown';
const HOME_KEY = 'Home';
const END_KEY = 'End';
const CLASS_NAME_ACTIVE = 'active';
const CLASS_NAME_FADE = 'fade';
const CLASS_NAME_SHOW = 'show';
const SELECTOR_DROPDOWN = '.dropdown';
const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';
const SELECTOR_ACTIVE = '.active';
const SELECTOR_ACTIVE_UL = ':scope > li > .active';
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]';
const CLASS_DROPDOWN = 'dropdown';
const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
const SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active';
const SELECTOR_DROPDOWN_MENU = '.dropdown-menu';
const NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`;
const SELECTOR_TAB_PANEL = '.list-group, .nav, [role="tablist"]';
const SELECTOR_OUTER = '.nav-item, .list-group-item';
const SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`;
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]'; // TODO: could only be `tab` in v6
const SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`;
const SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle="tab"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="pill"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="list"]`;
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
* Class definition
*/
class Tab extends BaseComponent__default.default {
class Tab extends BaseComponent {
constructor(element) {
super(element);
this._parent = this._element.closest(SELECTOR_TAB_PANEL);
if (!this._parent) {
return;
// TODO: should throw exception in v6
// throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)
}
// Set up initial aria attributes
this._setInitialAttributes(this._parent, this._getChildren());
EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event));
}
// Getters
static get NAME() {
return NAME;
} // Public
show() {
if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && this._element.classList.contains(CLASS_NAME_ACTIVE)) {
return;
}
let previous;
const target = getElementFromSelector(this._element);
const listElement = this._element.closest(SELECTOR_NAV_LIST_GROUP);
if (listElement) {
const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE;
previous = SelectorEngine__default.default.find(itemSelector, listElement);
previous = previous[previous.length - 1];
}
const hideEvent = previous ? EventHandler__default.default.trigger(previous, EVENT_HIDE, {
relatedTarget: this._element
}) : null;
const showEvent = EventHandler__default.default.trigger(this._element, EVENT_SHOW, {
relatedTarget: previous
});
if (showEvent.defaultPrevented || hideEvent !== null && hideEvent.defaultPrevented) {
return;
}
this._activate(this._element, listElement);
const complete = () => {
EventHandler__default.default.trigger(previous, EVENT_HIDDEN, {
relatedTarget: this._element
});
EventHandler__default.default.trigger(this._element, EVENT_SHOWN, {
relatedTarget: previous
});
};
if (target) {
this._activate(target, target.parentNode, complete);
} else {
complete();
}
} // Private
_activate(element, container, callback) {
const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ? SelectorEngine__default.default.find(SELECTOR_ACTIVE_UL, container) : SelectorEngine__default.default.children(container, SELECTOR_ACTIVE);
const active = activeElements[0];
const isTransitioning = callback && active && active.classList.contains(CLASS_NAME_FADE);
const complete = () => this._transitionComplete(element, active, callback);
if (active && isTransitioning) {
active.classList.remove(CLASS_NAME_SHOW);
this._queueCallback(complete, element, true);
} else {
complete();
}
}
_transitionComplete(element, active, callback) {
if (active) {
active.classList.remove(CLASS_NAME_ACTIVE);
const dropdownChild = SelectorEngine__default.default.findOne(SELECTOR_DROPDOWN_ACTIVE_CHILD, active.parentNode);
if (dropdownChild) {
dropdownChild.classList.remove(CLASS_NAME_ACTIVE);
}
if (active.getAttribute('role') === 'tab') {
active.setAttribute('aria-selected', false);
}
// Public
show() {
// Shows this elem and deactivate the active sibling if exists
const innerElem = this._element;
if (this._elemIsActive(innerElem)) {
return;
}
// Search for active tab on same parent to deactivate it
const active = this._getActiveElem();
const hideEvent = active ? EventHandler.trigger(active, EVENT_HIDE, {
relatedTarget: innerElem
}) : null;
const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, {
relatedTarget: active
});
if (showEvent.defaultPrevented || hideEvent && hideEvent.defaultPrevented) {
return;
}
this._deactivate(active, innerElem);
this._activate(innerElem, active);
}
// Private
_activate(element, relatedElem) {
if (!element) {
return;
}
element.classList.add(CLASS_NAME_ACTIVE);
this._activate(SelectorEngine.getElementFromSelector(element)); // Search and activate/show the proper section
if (element.getAttribute('role') === 'tab') {
element.setAttribute('aria-selected', true);
}
reflow(element);
if (element.classList.contains(CLASS_NAME_FADE)) {
element.classList.add(CLASS_NAME_SHOW);
}
let parent = element.parentNode;
if (parent && parent.nodeName === 'LI') {
parent = parent.parentNode;
}
if (parent && parent.classList.contains(CLASS_NAME_DROPDOWN_MENU)) {
const dropdownElement = element.closest(SELECTOR_DROPDOWN);
if (dropdownElement) {
SelectorEngine__default.default.find(SELECTOR_DROPDOWN_TOGGLE, dropdownElement).forEach(dropdown => dropdown.classList.add(CLASS_NAME_ACTIVE));
const complete = () => {
if (element.getAttribute('role') !== 'tab') {
element.classList.add(CLASS_NAME_SHOW);
return;
}
element.setAttribute('aria-expanded', true);
element.removeAttribute('tabindex');
element.setAttribute('aria-selected', true);
this._toggleDropDown(element, true);
EventHandler.trigger(element, EVENT_SHOWN, {
relatedTarget: relatedElem
});
};
this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE));
}
_deactivate(element, relatedElem) {
if (!element) {
return;
}
element.classList.remove(CLASS_NAME_ACTIVE);
element.blur();
this._deactivate(SelectorEngine.getElementFromSelector(element)); // Search and deactivate the shown section too
if (callback) {
callback();
const complete = () => {
if (element.getAttribute('role') !== 'tab') {
element.classList.remove(CLASS_NAME_SHOW);
return;
}
element.setAttribute('aria-selected', false);
element.setAttribute('tabindex', '-1');
this._toggleDropDown(element, false);
EventHandler.trigger(element, EVENT_HIDDEN, {
relatedTarget: relatedElem
});
};
this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE));
}
_keydown(event) {
if (![ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key)) {
return;
}
} // Static
event.stopPropagation(); // stopPropagation/preventDefault both added to support up/down keys without scrolling the page
event.preventDefault();
const children = this._getChildren().filter(element => !index_js.isDisabled(element));
let nextActiveElement;
if ([HOME_KEY, END_KEY].includes(event.key)) {
nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1];
} else {
const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key);
nextActiveElement = index_js.getNextActiveElement(children, event.target, isNext, true);
}
if (nextActiveElement) {
nextActiveElement.focus({
preventScroll: true
});
Tab.getOrCreateInstance(nextActiveElement).show();
}
}
_getChildren() {
// collection of inner elements
return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent);
}
_getActiveElem() {
return this._getChildren().find(child => this._elemIsActive(child)) || null;
}
_setInitialAttributes(parent, children) {
this._setAttributeIfNotExists(parent, 'role', 'tablist');
for (const child of children) {
this._setInitialAttributesOnChild(child);
}
}
_setInitialAttributesOnChild(child) {
child = this._getInnerElement(child);
const isActive = this._elemIsActive(child);
const outerElem = this._getOuterElement(child);
child.setAttribute('aria-selected', isActive);
if (outerElem !== child) {
this._setAttributeIfNotExists(outerElem, 'role', 'presentation');
}
if (!isActive) {
child.setAttribute('tabindex', '-1');
}
this._setAttributeIfNotExists(child, 'role', 'tab');
// set attributes to the related panel too
this._setInitialAttributesOnTargetPanel(child);
}
_setInitialAttributesOnTargetPanel(child) {
const target = SelectorEngine.getElementFromSelector(child);
if (!target) {
return;
}
this._setAttributeIfNotExists(target, 'role', 'tabpanel');
if (child.id) {
this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`);
}
}
_toggleDropDown(element, open) {
const outerElem = this._getOuterElement(element);
if (!outerElem.classList.contains(CLASS_DROPDOWN)) {
return;
}
const toggle = (selector, className) => {
const element = SelectorEngine.findOne(selector, outerElem);
if (element) {
element.classList.toggle(className, open);
}
};
toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE);
toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW);
outerElem.setAttribute('aria-expanded', open);
}
_setAttributeIfNotExists(element, attribute, value) {
if (!element.hasAttribute(attribute)) {
element.setAttribute(attribute, value);
}
}
_elemIsActive(elem) {
return elem.classList.contains(CLASS_NAME_ACTIVE);
}
// Try to get the inner element (usually the .nav-link)
_getInnerElement(elem) {
return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem);
}
// Try to get the outer element (usually the .nav-item)
_getOuterElement(elem) {
return elem.closest(SELECTOR_OUTER) || elem;
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Tab.getOrCreateInstance(this);
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
if (typeof config !== 'string') {
return;
}
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
* Data API implementation
*/
EventHandler__default.default.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault();
}
if (isDisabled(this)) {
if (index_js.isDisabled(this)) {
return;
}
Tab.getOrCreateInstance(this).show();
});
const data = Tab.getOrCreateInstance(this);
data.show();
/**
* Initialize on focus
*/
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {
Tab.getOrCreateInstance(element);
}
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .Tab to jQuery only if jQuery is present
*/
defineJQueryPlugin(Tab);
index_js.defineJQueryPlugin(Tab);
return Tab;

View file

@ -1,202 +1,24 @@
/*!
* Bootstrap toast.js v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap toast.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./base-component.js')) :
typeof define === 'function' && define.amd ? define(['./dom/event-handler', './dom/manipulator', './base-component'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Toast = factory(global.EventHandler, global.Manipulator, global.Base));
})(this, (function (EventHandler, Manipulator, BaseComponent) { 'use strict';
const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
const Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./util/component-functions.js'), require('./util/index.js')) :
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './util/component-functions', './util/index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Toast = factory(global.BaseComponent, global.EventHandler, global.ComponentFunctions, global.Index));
})(this, (function (BaseComponent, EventHandler, componentFunctions_js, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/index.js
* Bootstrap toast.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const toType = obj => {
if (obj === null || obj === undefined) {
return `${obj}`;
}
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
};
const getSelector = element => {
let selector = element.getAttribute('data-bs-target');
if (!selector || selector === '#') {
let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
// so everything starting with `#` or `.`. If a "real" URL is used as the selector,
// `document.querySelector` will rightfully complain it is invalid.
// See https://github.com/twbs/bootstrap/issues/32273
if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
return null;
} // Just in case some CMS puts out a full URL with the anchor appended
if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
hrefAttr = `#${hrefAttr.split('#')[1]}`;
}
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
}
return selector;
};
const getElementFromSelector = element => {
const selector = getSelector(element);
return selector ? document.querySelector(selector) : null;
};
const isElement = obj => {
if (!obj || typeof obj !== 'object') {
return false;
}
if (typeof obj.jquery !== 'undefined') {
obj = obj[0];
}
return typeof obj.nodeType !== 'undefined';
};
const typeCheckConfig = (componentName, config, configTypes) => {
Object.keys(configTypes).forEach(property => {
const expectedTypes = configTypes[property];
const value = config[property];
const valueType = value && isElement(value) ? 'element' : toType(value);
if (!new RegExp(expectedTypes).test(valueType)) {
throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
}
});
};
const isDisabled = element => {
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
return true;
}
if (element.classList.contains('disabled')) {
return true;
}
if (typeof element.disabled !== 'undefined') {
return element.disabled;
}
return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
};
/**
* Trick to restart an element's animation
*
* @param {HTMLElement} element
* @return void
*
* @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
*/
const reflow = element => {
// eslint-disable-next-line no-unused-expressions
element.offsetHeight;
};
const getjQuery = () => {
const {
jQuery
} = window;
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
return jQuery;
}
return null;
};
const DOMContentLoadedCallbacks = [];
const onDOMContentLoaded = callback => {
if (document.readyState === 'loading') {
// add listener on the first call when the document is in loading state
if (!DOMContentLoadedCallbacks.length) {
document.addEventListener('DOMContentLoaded', () => {
DOMContentLoadedCallbacks.forEach(callback => callback());
});
}
DOMContentLoadedCallbacks.push(callback);
} else {
callback();
}
};
const defineJQueryPlugin = plugin => {
onDOMContentLoaded(() => {
const $ = getjQuery();
/* istanbul ignore if */
if ($) {
const name = plugin.NAME;
const JQUERY_NO_CONFLICT = $.fn[name];
$.fn[name] = plugin.jQueryInterface;
$.fn[name].Constructor = plugin;
$.fn[name].noConflict = () => {
$.fn[name] = JQUERY_NO_CONFLICT;
return plugin.jQueryInterface;
};
}
});
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): util/component-functions.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const enableDismissTrigger = (component, method = 'hide') => {
const clickEvent = `click.dismiss${component.EVENT_KEY}`;
const name = component.NAME;
EventHandler__default.default.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault();
}
if (isDisabled(this)) {
return;
}
const target = getElementFromSelector(this) || this.closest(`.${name}`);
const instance = component.getOrCreateInstance(target); // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
instance[method]();
});
};
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.1.3): toast.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'toast';
@ -212,7 +34,6 @@
const EVENT_SHOWN = `shown${EVENT_KEY}`;
const CLASS_NAME_FADE = 'fade';
const CLASS_NAME_HIDE = 'hide'; // @deprecated - kept here only for backwards compatibility
const CLASS_NAME_SHOW = 'show';
const CLASS_NAME_SHOWING = 'showing';
const DefaultType = {
@ -225,197 +46,152 @@
autohide: true,
delay: 5000
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
* Class definition
*/
class Toast extends BaseComponent__default.default {
class Toast extends BaseComponent {
constructor(element, config) {
super(element);
this._config = this._getConfig(config);
super(element, config);
this._timeout = null;
this._hasMouseInteraction = false;
this._hasKeyboardInteraction = false;
this._setListeners();
} // Getters
static get DefaultType() {
return DefaultType;
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
} // Public
}
// Public
show() {
const showEvent = EventHandler__default.default.trigger(this._element, EVENT_SHOW);
const showEvent = EventHandler.trigger(this._element, EVENT_SHOW);
if (showEvent.defaultPrevented) {
return;
}
this._clearTimeout();
if (this._config.animation) {
this._element.classList.add(CLASS_NAME_FADE);
}
const complete = () => {
this._element.classList.remove(CLASS_NAME_SHOWING);
EventHandler__default.default.trigger(this._element, EVENT_SHOWN);
EventHandler.trigger(this._element, EVENT_SHOWN);
this._maybeScheduleHide();
};
this._element.classList.remove(CLASS_NAME_HIDE); // @deprecated
reflow(this._element);
this._element.classList.add(CLASS_NAME_SHOW);
this._element.classList.add(CLASS_NAME_SHOWING);
index_js.reflow(this._element);
this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING);
this._queueCallback(complete, this._element, this._config.animation);
}
hide() {
if (!this._element.classList.contains(CLASS_NAME_SHOW)) {
if (!this.isShown()) {
return;
}
const hideEvent = EventHandler__default.default.trigger(this._element, EVENT_HIDE);
const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE);
if (hideEvent.defaultPrevented) {
return;
}
const complete = () => {
this._element.classList.add(CLASS_NAME_HIDE); // @deprecated
this._element.classList.remove(CLASS_NAME_SHOWING);
this._element.classList.remove(CLASS_NAME_SHOW);
EventHandler__default.default.trigger(this._element, EVENT_HIDDEN);
this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW);
EventHandler.trigger(this._element, EVENT_HIDDEN);
};
this._element.classList.add(CLASS_NAME_SHOWING);
this._queueCallback(complete, this._element, this._config.animation);
}
dispose() {
this._clearTimeout();
if (this._element.classList.contains(CLASS_NAME_SHOW)) {
if (this.isShown()) {
this._element.classList.remove(CLASS_NAME_SHOW);
}
super.dispose();
} // Private
_getConfig(config) {
config = { ...Default,
...Manipulator__default.default.getDataAttributes(this._element),
...(typeof config === 'object' && config ? config : {})
};
typeCheckConfig(NAME, config, this.constructor.DefaultType);
return config;
}
isShown() {
return this._element.classList.contains(CLASS_NAME_SHOW);
}
// Private
_maybeScheduleHide() {
if (!this._config.autohide) {
return;
}
if (this._hasMouseInteraction || this._hasKeyboardInteraction) {
return;
}
this._timeout = setTimeout(() => {
this.hide();
}, this._config.delay);
}
_onInteraction(event, isInteracting) {
switch (event.type) {
case 'mouseover':
case 'mouseout':
this._hasMouseInteraction = isInteracting;
break;
{
this._hasMouseInteraction = isInteracting;
break;
}
case 'focusin':
case 'focusout':
this._hasKeyboardInteraction = isInteracting;
break;
{
this._hasKeyboardInteraction = isInteracting;
break;
}
}
if (isInteracting) {
this._clearTimeout();
return;
}
const nextElement = event.relatedTarget;
if (this._element === nextElement || this._element.contains(nextElement)) {
return;
}
this._maybeScheduleHide();
}
_setListeners() {
EventHandler__default.default.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true));
EventHandler__default.default.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false));
EventHandler__default.default.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true));
EventHandler__default.default.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false));
EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true));
EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false));
EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true));
EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false));
}
_clearTimeout() {
clearTimeout(this._timeout);
this._timeout = null;
} // Static
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Toast.getOrCreateInstance(this, config);
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config](this);
}
});
}
}
enableDismissTrigger(Toast);
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
* add .Toast to jQuery only if jQuery is present
* Data API implementation
*/
defineJQueryPlugin(Toast);
componentFunctions_js.enableDismissTrigger(Toast);
/**
* jQuery
*/
index_js.defineJQueryPlugin(Toast);
return Toast;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,139 @@
/*!
* Bootstrap backdrop.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/event-handler.js'), require('./config.js'), require('./index.js')) :
typeof define === 'function' && define.amd ? define(['../dom/event-handler', './config', './index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Backdrop = factory(global.EventHandler, global.Config, global.Index));
})(this, (function (EventHandler, Config, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap util/backdrop.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const NAME = 'backdrop';
const CLASS_NAME_FADE = 'fade';
const CLASS_NAME_SHOW = 'show';
const EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`;
const Default = {
className: 'modal-backdrop',
clickCallback: null,
isAnimated: false,
isVisible: true,
// if false, we use the backdrop helper without adding any element to the dom
rootElement: 'body' // give the choice to place backdrop under different elements
};
const DefaultType = {
className: 'string',
clickCallback: '(function|null)',
isAnimated: 'boolean',
isVisible: 'boolean',
rootElement: '(element|string)'
};
/**
* Class definition
*/
class Backdrop extends Config {
constructor(config) {
super();
this._config = this._getConfig(config);
this._isAppended = false;
this._element = null;
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
}
// Public
show(callback) {
if (!this._config.isVisible) {
index_js.execute(callback);
return;
}
this._append();
const element = this._getElement();
if (this._config.isAnimated) {
index_js.reflow(element);
}
element.classList.add(CLASS_NAME_SHOW);
this._emulateAnimation(() => {
index_js.execute(callback);
});
}
hide(callback) {
if (!this._config.isVisible) {
index_js.execute(callback);
return;
}
this._getElement().classList.remove(CLASS_NAME_SHOW);
this._emulateAnimation(() => {
this.dispose();
index_js.execute(callback);
});
}
dispose() {
if (!this._isAppended) {
return;
}
EventHandler.off(this._element, EVENT_MOUSEDOWN);
this._element.remove();
this._isAppended = false;
}
// Private
_getElement() {
if (!this._element) {
const backdrop = document.createElement('div');
backdrop.className = this._config.className;
if (this._config.isAnimated) {
backdrop.classList.add(CLASS_NAME_FADE);
}
this._element = backdrop;
}
return this._element;
}
_configAfterMerge(config) {
// use getElement() with the default "body" to get a fresh Element on each instantiation
config.rootElement = index_js.getElement(config.rootElement);
return config;
}
_append() {
if (this._isAppended) {
return;
}
const element = this._getElement();
this._config.rootElement.append(element);
EventHandler.on(element, EVENT_MOUSEDOWN, () => {
index_js.execute(this._config.clickCallback);
});
this._isAppended = true;
}
_emulateAnimation(callback) {
index_js.executeAfterTransition(callback, this._getElement(), this._config.isAnimated);
}
}
return Backdrop;
}));
//# sourceMappingURL=backdrop.js.map

View file

@ -0,0 +1,42 @@
/*!
* Bootstrap component-functions.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('../dom/event-handler.js'), require('../dom/selector-engine.js'), require('./index.js')) :
typeof define === 'function' && define.amd ? define(['exports', '../dom/event-handler', '../dom/selector-engine', './index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ComponentFunctions = {}, global.EventHandler, global.SelectorEngine, global.Index));
})(this, (function (exports, EventHandler, SelectorEngine, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap util/component-functions.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const enableDismissTrigger = (component, method = 'hide') => {
const clickEvent = `click.dismiss${component.EVENT_KEY}`;
const name = component.NAME;
EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault();
}
if (index_js.isDisabled(this)) {
return;
}
const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`);
const instance = component.getOrCreateInstance(target);
// Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
instance[method]();
});
};
exports.enableDismissTrigger = enableDismissTrigger;
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}));
//# sourceMappingURL=component-functions.js.map

View file

@ -0,0 +1,68 @@
/*!
* Bootstrap config.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/manipulator.js'), require('./index.js')) :
typeof define === 'function' && define.amd ? define(['../dom/manipulator', './index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Config = factory(global.Manipulator, global.Index));
})(this, (function (Manipulator, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap util/config.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Class definition
*/
class Config {
// Getters
static get Default() {
return {};
}
static get DefaultType() {
return {};
}
static get NAME() {
throw new Error('You have to implement the static method "NAME", for each component!');
}
_getConfig(config) {
config = this._mergeConfigObj(config);
config = this._configAfterMerge(config);
this._typeCheckConfig(config);
return config;
}
_configAfterMerge(config) {
return config;
}
_mergeConfigObj(config, element) {
const jsonConfig = index_js.isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {}; // try to parse
return {
...this.constructor.Default,
...(typeof jsonConfig === 'object' ? jsonConfig : {}),
...(index_js.isElement(element) ? Manipulator.getDataAttributes(element) : {}),
...(typeof config === 'object' ? config : {})
};
}
_typeCheckConfig(config, configTypes = this.constructor.DefaultType) {
for (const [property, expectedTypes] of Object.entries(configTypes)) {
const value = config[property];
const valueType = index_js.isElement(value) ? 'element' : index_js.toType(value);
if (!new RegExp(expectedTypes).test(valueType)) {
throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
}
}
}
}
return Config;
}));
//# sourceMappingURL=config.js.map

View file

@ -0,0 +1,113 @@
/*!
* Bootstrap focustrap.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/event-handler.js'), require('../dom/selector-engine.js'), require('./config.js')) :
typeof define === 'function' && define.amd ? define(['../dom/event-handler', '../dom/selector-engine', './config'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Focustrap = factory(global.EventHandler, global.SelectorEngine, global.Config));
})(this, (function (EventHandler, SelectorEngine, Config) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap util/focustrap.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const NAME = 'focustrap';
const DATA_KEY = 'bs.focustrap';
const EVENT_KEY = `.${DATA_KEY}`;
const EVENT_FOCUSIN = `focusin${EVENT_KEY}`;
const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`;
const TAB_KEY = 'Tab';
const TAB_NAV_FORWARD = 'forward';
const TAB_NAV_BACKWARD = 'backward';
const Default = {
autofocus: true,
trapElement: null // The element to trap focus inside of
};
const DefaultType = {
autofocus: 'boolean',
trapElement: 'element'
};
/**
* Class definition
*/
class FocusTrap extends Config {
constructor(config) {
super();
this._config = this._getConfig(config);
this._isActive = false;
this._lastTabNavDirection = null;
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
}
// Public
activate() {
if (this._isActive) {
return;
}
if (this._config.autofocus) {
this._config.trapElement.focus();
}
EventHandler.off(document, EVENT_KEY); // guard against infinite focus loop
EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event));
EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));
this._isActive = true;
}
deactivate() {
if (!this._isActive) {
return;
}
this._isActive = false;
EventHandler.off(document, EVENT_KEY);
}
// Private
_handleFocusin(event) {
const {
trapElement
} = this._config;
if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {
return;
}
const elements = SelectorEngine.focusableChildren(trapElement);
if (elements.length === 0) {
trapElement.focus();
} else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
elements[elements.length - 1].focus();
} else {
elements[0].focus();
}
}
_handleKeydown(event) {
if (event.key !== TAB_KEY) {
return;
}
this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;
}
}
return FocusTrap;
}));
//# sourceMappingURL=focustrap.js.map

View file

@ -0,0 +1,281 @@
/*!
* Bootstrap index.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Index = {}));
})(this, (function (exports) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap util/index.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
const MAX_UID = 1000000;
const MILLISECONDS_MULTIPLIER = 1000;
const TRANSITION_END = 'transitionend';
/**
* Properly escape IDs selectors to handle weird IDs
* @param {string} selector
* @returns {string}
*/
const parseSelector = selector => {
if (selector && window.CSS && window.CSS.escape) {
// document.querySelector needs escaping to handle IDs (html5+) containing for instance /
selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`);
}
return selector;
};
// Shout-out Angus Croll (https://goo.gl/pxwQGp)
const toType = object => {
if (object === null || object === undefined) {
return `${object}`;
}
return Object.prototype.toString.call(object).match(/\s([a-z]+)/i)[1].toLowerCase();
};
/**
* Public Util API
*/
const getUID = prefix => {
do {
prefix += Math.floor(Math.random() * MAX_UID);
} while (document.getElementById(prefix));
return prefix;
};
const getTransitionDurationFromElement = element => {
if (!element) {
return 0;
}
// Get transition-duration of the element
let {
transitionDuration,
transitionDelay
} = window.getComputedStyle(element);
const floatTransitionDuration = Number.parseFloat(transitionDuration);
const floatTransitionDelay = Number.parseFloat(transitionDelay);
// Return 0 if element or transition duration is not found
if (!floatTransitionDuration && !floatTransitionDelay) {
return 0;
}
// If multiple durations are defined, take the first
transitionDuration = transitionDuration.split(',')[0];
transitionDelay = transitionDelay.split(',')[0];
return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;
};
const triggerTransitionEnd = element => {
element.dispatchEvent(new Event(TRANSITION_END));
};
const isElement = object => {
if (!object || typeof object !== 'object') {
return false;
}
if (typeof object.jquery !== 'undefined') {
object = object[0];
}
return typeof object.nodeType !== 'undefined';
};
const getElement = object => {
// it's a jQuery object or a node element
if (isElement(object)) {
return object.jquery ? object[0] : object;
}
if (typeof object === 'string' && object.length > 0) {
return document.querySelector(parseSelector(object));
}
return null;
};
const isVisible = element => {
if (!isElement(element) || element.getClientRects().length === 0) {
return false;
}
const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible';
// Handle `details` element as its content may falsie appear visible when it is closed
const closedDetails = element.closest('details:not([open])');
if (!closedDetails) {
return elementIsVisible;
}
if (closedDetails !== element) {
const summary = element.closest('summary');
if (summary && summary.parentNode !== closedDetails) {
return false;
}
if (summary === null) {
return false;
}
}
return elementIsVisible;
};
const isDisabled = element => {
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
return true;
}
if (element.classList.contains('disabled')) {
return true;
}
if (typeof element.disabled !== 'undefined') {
return element.disabled;
}
return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
};
const findShadowRoot = element => {
if (!document.documentElement.attachShadow) {
return null;
}
// Can find the shadow root otherwise it'll return the document
if (typeof element.getRootNode === 'function') {
const root = element.getRootNode();
return root instanceof ShadowRoot ? root : null;
}
if (element instanceof ShadowRoot) {
return element;
}
// when we don't find a shadow root
if (!element.parentNode) {
return null;
}
return findShadowRoot(element.parentNode);
};
const noop = () => {};
/**
* Trick to restart an element's animation
*
* @param {HTMLElement} element
* @return void
*
* @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
*/
const reflow = element => {
element.offsetHeight; // eslint-disable-line no-unused-expressions
};
const getjQuery = () => {
if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
return window.jQuery;
}
return null;
};
const DOMContentLoadedCallbacks = [];
const onDOMContentLoaded = callback => {
if (document.readyState === 'loading') {
// add listener on the first call when the document is in loading state
if (!DOMContentLoadedCallbacks.length) {
document.addEventListener('DOMContentLoaded', () => {
for (const callback of DOMContentLoadedCallbacks) {
callback();
}
});
}
DOMContentLoadedCallbacks.push(callback);
} else {
callback();
}
};
const isRTL = () => document.documentElement.dir === 'rtl';
const defineJQueryPlugin = plugin => {
onDOMContentLoaded(() => {
const $ = getjQuery();
/* istanbul ignore if */
if ($) {
const name = plugin.NAME;
const JQUERY_NO_CONFLICT = $.fn[name];
$.fn[name] = plugin.jQueryInterface;
$.fn[name].Constructor = plugin;
$.fn[name].noConflict = () => {
$.fn[name] = JQUERY_NO_CONFLICT;
return plugin.jQueryInterface;
};
}
});
};
const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {
return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue;
};
const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
if (!waitForTransition) {
execute(callback);
return;
}
const durationPadding = 5;
const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;
let called = false;
const handler = ({
target
}) => {
if (target !== transitionElement) {
return;
}
called = true;
transitionElement.removeEventListener(TRANSITION_END, handler);
execute(callback);
};
transitionElement.addEventListener(TRANSITION_END, handler);
setTimeout(() => {
if (!called) {
triggerTransitionEnd(transitionElement);
}
}, emulatedDuration);
};
/**
* Return the previous/next element of a list.
*
* @param {array} list The list of elements
* @param activeElement The active element
* @param shouldGetNext Choose to get next or previous element
* @param isCycleAllowed
* @return {Element|elem} The proper element
*/
const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
const listLength = list.length;
let index = list.indexOf(activeElement);
// if the element does not exist in the list return an element
// depending on the direction and if cycle is allowed
if (index === -1) {
return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0];
}
index += shouldGetNext ? 1 : -1;
if (isCycleAllowed) {
index = (index + listLength) % listLength;
}
return list[Math.max(0, Math.min(index, listLength - 1))];
};
exports.defineJQueryPlugin = defineJQueryPlugin;
exports.execute = execute;
exports.executeAfterTransition = executeAfterTransition;
exports.findShadowRoot = findShadowRoot;
exports.getElement = getElement;
exports.getNextActiveElement = getNextActiveElement;
exports.getTransitionDurationFromElement = getTransitionDurationFromElement;
exports.getUID = getUID;
exports.getjQuery = getjQuery;
exports.isDisabled = isDisabled;
exports.isElement = isElement;
exports.isRTL = isRTL;
exports.isVisible = isVisible;
exports.noop = noop;
exports.onDOMContentLoaded = onDOMContentLoaded;
exports.parseSelector = parseSelector;
exports.reflow = reflow;
exports.toType = toType;
exports.triggerTransitionEnd = triggerTransitionEnd;
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}));
//# sourceMappingURL=index.js.map

View file

@ -0,0 +1,114 @@
/*!
* Bootstrap sanitizer.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Sanitizer = {}));
})(this, (function (exports) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap util/sanitizer.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
// js-docs-start allow-list
const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
const DefaultAllowlist = {
// Global attributes allowed on any supplied element below.
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
a: ['target', 'href', 'title', 'rel'],
area: [],
b: [],
br: [],
col: [],
code: [],
dd: [],
div: [],
dl: [],
dt: [],
em: [],
hr: [],
h1: [],
h2: [],
h3: [],
h4: [],
h5: [],
h6: [],
i: [],
img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
li: [],
ol: [],
p: [],
pre: [],
s: [],
small: [],
span: [],
sub: [],
sup: [],
strong: [],
u: [],
ul: []
};
// js-docs-end allow-list
const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);
/**
* A pattern that recognizes URLs that are safe wrt. XSS in URL navigation
* contexts.
*
* Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38
*/
// eslint-disable-next-line unicorn/better-regex
const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i;
const allowedAttribute = (attribute, allowedAttributeList) => {
const attributeName = attribute.nodeName.toLowerCase();
if (allowedAttributeList.includes(attributeName)) {
if (uriAttributes.has(attributeName)) {
return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue));
}
return true;
}
// Check if a regular expression validates the attribute.
return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName));
};
function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
if (!unsafeHtml.length) {
return unsafeHtml;
}
if (sanitizeFunction && typeof sanitizeFunction === 'function') {
return sanitizeFunction(unsafeHtml);
}
const domParser = new window.DOMParser();
const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
const elements = [].concat(...createdDocument.body.querySelectorAll('*'));
for (const element of elements) {
const elementName = element.nodeName.toLowerCase();
if (!Object.keys(allowList).includes(elementName)) {
element.remove();
continue;
}
const attributeList = [].concat(...element.attributes);
const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);
for (const attribute of attributeList) {
if (!allowedAttribute(attribute, allowedAttributes)) {
element.removeAttribute(attribute.nodeName);
}
}
}
return createdDocument.body.innerHTML;
}
exports.DefaultAllowlist = DefaultAllowlist;
exports.sanitizeHtml = sanitizeHtml;
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}));
//# sourceMappingURL=sanitizer.js.map

View file

@ -0,0 +1,113 @@
/*!
* Bootstrap scrollbar.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/manipulator.js'), require('../dom/selector-engine.js'), require('./index.js')) :
typeof define === 'function' && define.amd ? define(['../dom/manipulator', '../dom/selector-engine', './index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Scrollbar = factory(global.Manipulator, global.SelectorEngine, global.Index));
})(this, (function (Manipulator, SelectorEngine, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap util/scrollBar.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
const SELECTOR_STICKY_CONTENT = '.sticky-top';
const PROPERTY_PADDING = 'padding-right';
const PROPERTY_MARGIN = 'margin-right';
/**
* Class definition
*/
class ScrollBarHelper {
constructor() {
this._element = document.body;
}
// Public
getWidth() {
// https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
const documentWidth = document.documentElement.clientWidth;
return Math.abs(window.innerWidth - documentWidth);
}
hide() {
const width = this.getWidth();
this._disableOverFlow();
// give padding to element to balance the hidden scrollbar width
this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width);
// trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width);
this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width);
}
reset() {
this._resetElementAttributes(this._element, 'overflow');
this._resetElementAttributes(this._element, PROPERTY_PADDING);
this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING);
this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN);
}
isOverflowing() {
return this.getWidth() > 0;
}
// Private
_disableOverFlow() {
this._saveInitialAttribute(this._element, 'overflow');
this._element.style.overflow = 'hidden';
}
_setElementAttributes(selector, styleProperty, callback) {
const scrollbarWidth = this.getWidth();
const manipulationCallBack = element => {
if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
return;
}
this._saveInitialAttribute(element, styleProperty);
const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty);
element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`);
};
this._applyManipulationCallback(selector, manipulationCallBack);
}
_saveInitialAttribute(element, styleProperty) {
const actualValue = element.style.getPropertyValue(styleProperty);
if (actualValue) {
Manipulator.setDataAttribute(element, styleProperty, actualValue);
}
}
_resetElementAttributes(selector, styleProperty) {
const manipulationCallBack = element => {
const value = Manipulator.getDataAttribute(element, styleProperty);
// We only want to remove the property if the value is `null`; the value can also be zero
if (value === null) {
element.style.removeProperty(styleProperty);
return;
}
Manipulator.removeDataAttribute(element, styleProperty);
element.style.setProperty(styleProperty, value);
};
this._applyManipulationCallback(selector, manipulationCallBack);
}
_applyManipulationCallback(selector, callBack) {
if (index_js.isElement(selector)) {
callBack(selector);
return;
}
for (const sel of SelectorEngine.find(selector, this._element)) {
callBack(sel);
}
}
}
return ScrollBarHelper;
}));
//# sourceMappingURL=scrollbar.js.map

View file

@ -0,0 +1,135 @@
/*!
* Bootstrap swipe.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/event-handler.js'), require('./config.js'), require('./index.js')) :
typeof define === 'function' && define.amd ? define(['../dom/event-handler', './config', './index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Swipe = factory(global.EventHandler, global.Config, global.Index));
})(this, (function (EventHandler, Config, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap util/swipe.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const NAME = 'swipe';
const EVENT_KEY = '.bs.swipe';
const EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`;
const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`;
const EVENT_TOUCHEND = `touchend${EVENT_KEY}`;
const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`;
const EVENT_POINTERUP = `pointerup${EVENT_KEY}`;
const POINTER_TYPE_TOUCH = 'touch';
const POINTER_TYPE_PEN = 'pen';
const CLASS_NAME_POINTER_EVENT = 'pointer-event';
const SWIPE_THRESHOLD = 40;
const Default = {
endCallback: null,
leftCallback: null,
rightCallback: null
};
const DefaultType = {
endCallback: '(function|null)',
leftCallback: '(function|null)',
rightCallback: '(function|null)'
};
/**
* Class definition
*/
class Swipe extends Config {
constructor(element, config) {
super();
this._element = element;
if (!element || !Swipe.isSupported()) {
return;
}
this._config = this._getConfig(config);
this._deltaX = 0;
this._supportPointerEvents = Boolean(window.PointerEvent);
this._initEvents();
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
}
// Public
dispose() {
EventHandler.off(this._element, EVENT_KEY);
}
// Private
_start(event) {
if (!this._supportPointerEvents) {
this._deltaX = event.touches[0].clientX;
return;
}
if (this._eventIsPointerPenTouch(event)) {
this._deltaX = event.clientX;
}
}
_end(event) {
if (this._eventIsPointerPenTouch(event)) {
this._deltaX = event.clientX - this._deltaX;
}
this._handleSwipe();
index_js.execute(this._config.endCallback);
}
_move(event) {
this._deltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this._deltaX;
}
_handleSwipe() {
const absDeltaX = Math.abs(this._deltaX);
if (absDeltaX <= SWIPE_THRESHOLD) {
return;
}
const direction = absDeltaX / this._deltaX;
this._deltaX = 0;
if (!direction) {
return;
}
index_js.execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback);
}
_initEvents() {
if (this._supportPointerEvents) {
EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event));
EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event));
this._element.classList.add(CLASS_NAME_POINTER_EVENT);
} else {
EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event));
EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event));
EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event));
}
}
_eventIsPointerPenTouch(event) {
return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH);
}
// Static
static isSupported() {
return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;
}
}
return Swipe;
}));
//# sourceMappingURL=swipe.js.map

View file

@ -0,0 +1,151 @@
/*!
* Bootstrap template-factory.js v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/selector-engine.js'), require('./config.js'), require('./sanitizer.js'), require('./index.js')) :
typeof define === 'function' && define.amd ? define(['../dom/selector-engine', './config', './sanitizer', './index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.TemplateFactory = factory(global.SelectorEngine, global.Config, global.Sanitizer, global.Index));
})(this, (function (SelectorEngine, Config, sanitizer_js, index_js) { 'use strict';
/**
* --------------------------------------------------------------------------
* Bootstrap util/template-factory.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
const NAME = 'TemplateFactory';
const Default = {
allowList: sanitizer_js.DefaultAllowlist,
content: {},
// { selector : text , selector2 : text2 , }
extraClass: '',
html: false,
sanitize: true,
sanitizeFn: null,
template: '<div></div>'
};
const DefaultType = {
allowList: 'object',
content: 'object',
extraClass: '(string|function)',
html: 'boolean',
sanitize: 'boolean',
sanitizeFn: '(null|function)',
template: 'string'
};
const DefaultContentType = {
entry: '(string|element|function|null)',
selector: '(string|element)'
};
/**
* Class definition
*/
class TemplateFactory extends Config {
constructor(config) {
super();
this._config = this._getConfig(config);
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
}
// Public
getContent() {
return Object.values(this._config.content).map(config => this._resolvePossibleFunction(config)).filter(Boolean);
}
hasContent() {
return this.getContent().length > 0;
}
changeContent(content) {
this._checkContent(content);
this._config.content = {
...this._config.content,
...content
};
return this;
}
toHtml() {
const templateWrapper = document.createElement('div');
templateWrapper.innerHTML = this._maybeSanitize(this._config.template);
for (const [selector, text] of Object.entries(this._config.content)) {
this._setContent(templateWrapper, text, selector);
}
const template = templateWrapper.children[0];
const extraClass = this._resolvePossibleFunction(this._config.extraClass);
if (extraClass) {
template.classList.add(...extraClass.split(' '));
}
return template;
}
// Private
_typeCheckConfig(config) {
super._typeCheckConfig(config);
this._checkContent(config.content);
}
_checkContent(arg) {
for (const [selector, content] of Object.entries(arg)) {
super._typeCheckConfig({
selector,
entry: content
}, DefaultContentType);
}
}
_setContent(template, content, selector) {
const templateElement = SelectorEngine.findOne(selector, template);
if (!templateElement) {
return;
}
content = this._resolvePossibleFunction(content);
if (!content) {
templateElement.remove();
return;
}
if (index_js.isElement(content)) {
this._putElementInTemplate(index_js.getElement(content), templateElement);
return;
}
if (this._config.html) {
templateElement.innerHTML = this._maybeSanitize(content);
return;
}
templateElement.textContent = content;
}
_maybeSanitize(arg) {
return this._config.sanitize ? sanitizer_js.sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg;
}
_resolvePossibleFunction(arg) {
return index_js.execute(arg, [this]);
}
_putElementInTemplate(element, templateElement) {
if (this._config.html) {
templateElement.innerHTML = '';
templateElement.append(element);
return;
}
templateElement.textContent = element.textContent;
}
}
return TemplateFactory;
}));
//# sourceMappingURL=template-factory.js.map

View file

@ -2,43 +2,69 @@
// Base styles
//
.accordion {
// scss-docs-start accordion-css-vars
--#{$prefix}accordion-color: #{$accordion-color};
--#{$prefix}accordion-bg: #{$accordion-bg};
--#{$prefix}accordion-transition: #{$accordion-transition};
--#{$prefix}accordion-border-color: #{$accordion-border-color};
--#{$prefix}accordion-border-width: #{$accordion-border-width};
--#{$prefix}accordion-border-radius: #{$accordion-border-radius};
--#{$prefix}accordion-inner-border-radius: #{$accordion-inner-border-radius};
--#{$prefix}accordion-btn-padding-x: #{$accordion-button-padding-x};
--#{$prefix}accordion-btn-padding-y: #{$accordion-button-padding-y};
--#{$prefix}accordion-btn-color: #{$accordion-button-color};
--#{$prefix}accordion-btn-bg: #{$accordion-button-bg};
--#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon)};
--#{$prefix}accordion-btn-icon-width: #{$accordion-icon-width};
--#{$prefix}accordion-btn-icon-transform: #{$accordion-icon-transform};
--#{$prefix}accordion-btn-icon-transition: #{$accordion-icon-transition};
--#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon)};
--#{$prefix}accordion-btn-focus-box-shadow: #{$accordion-button-focus-box-shadow};
--#{$prefix}accordion-body-padding-x: #{$accordion-body-padding-x};
--#{$prefix}accordion-body-padding-y: #{$accordion-body-padding-y};
--#{$prefix}accordion-active-color: #{$accordion-button-active-color};
--#{$prefix}accordion-active-bg: #{$accordion-button-active-bg};
// scss-docs-end accordion-css-vars
}
.accordion-button {
position: relative;
display: flex;
align-items: center;
width: 100%;
padding: $accordion-button-padding-y $accordion-button-padding-x;
padding: var(--#{$prefix}accordion-btn-padding-y) var(--#{$prefix}accordion-btn-padding-x);
@include font-size($font-size-base);
color: $accordion-button-color;
color: var(--#{$prefix}accordion-btn-color);
text-align: left; // Reset button style
background-color: $accordion-button-bg;
background-color: var(--#{$prefix}accordion-btn-bg);
border: 0;
@include border-radius(0);
overflow-anchor: none;
@include transition($accordion-transition);
@include transition(var(--#{$prefix}accordion-transition));
&:not(.collapsed) {
color: $accordion-button-active-color;
background-color: $accordion-button-active-bg;
box-shadow: inset 0 ($accordion-border-width * -1) 0 $accordion-border-color;
color: var(--#{$prefix}accordion-active-color);
background-color: var(--#{$prefix}accordion-active-bg);
box-shadow: inset 0 calc(-1 * var(--#{$prefix}accordion-border-width)) 0 var(--#{$prefix}accordion-border-color); // stylelint-disable-line function-disallowed-list
&::after {
background-image: escape-svg($accordion-button-active-icon);
transform: $accordion-icon-transform;
background-image: var(--#{$prefix}accordion-btn-active-icon);
transform: var(--#{$prefix}accordion-btn-icon-transform);
}
}
// Accordion icon
&::after {
flex-shrink: 0;
width: $accordion-icon-width;
height: $accordion-icon-width;
width: var(--#{$prefix}accordion-btn-icon-width);
height: var(--#{$prefix}accordion-btn-icon-width);
margin-left: auto;
content: "";
background-image: escape-svg($accordion-button-icon);
background-image: var(--#{$prefix}accordion-btn-icon);
background-repeat: no-repeat;
background-size: $accordion-icon-width;
@include transition($accordion-icon-transition);
background-size: var(--#{$prefix}accordion-btn-icon-width);
@include transition(var(--#{$prefix}accordion-btn-icon-transition));
}
&:hover {
@ -47,9 +73,8 @@
&:focus {
z-index: 3;
border-color: $accordion-button-focus-border-color;
outline: 0;
box-shadow: $accordion-button-focus-box-shadow;
box-shadow: var(--#{$prefix}accordion-btn-focus-box-shadow);
}
}
@ -58,14 +83,15 @@
}
.accordion-item {
background-color: $accordion-bg;
border: $accordion-border-width solid $accordion-border-color;
color: var(--#{$prefix}accordion-color);
background-color: var(--#{$prefix}accordion-bg);
border: var(--#{$prefix}accordion-border-width) solid var(--#{$prefix}accordion-border-color);
&:first-of-type {
@include border-top-radius($accordion-border-radius);
@include border-top-radius(var(--#{$prefix}accordion-border-radius));
.accordion-button {
@include border-top-radius($accordion-inner-border-radius);
> .accordion-header .accordion-button {
@include border-top-radius(var(--#{$prefix}accordion-inner-border-radius));
}
}
@ -75,22 +101,22 @@
// Only set a border-radius on the last item if the accordion is collapsed
&:last-of-type {
@include border-bottom-radius($accordion-border-radius);
@include border-bottom-radius(var(--#{$prefix}accordion-border-radius));
.accordion-button {
> .accordion-header .accordion-button {
&.collapsed {
@include border-bottom-radius($accordion-inner-border-radius);
@include border-bottom-radius(var(--#{$prefix}accordion-inner-border-radius));
}
}
.accordion-collapse {
@include border-bottom-radius($accordion-border-radius);
> .accordion-collapse {
@include border-bottom-radius(var(--#{$prefix}accordion-border-radius));
}
}
}
.accordion-body {
padding: $accordion-body-padding-y $accordion-body-padding-x;
padding: var(--#{$prefix}accordion-body-padding-y) var(--#{$prefix}accordion-body-padding-x);
}
@ -99,11 +125,7 @@
// Remove borders and border-radius to keep accordion items edge-to-edge.
.accordion-flush {
.accordion-collapse {
border-width: 0;
}
.accordion-item {
> .accordion-item {
border-right: 0;
border-left: 0;
@include border-radius(0);
@ -111,8 +133,26 @@
&:first-child { border-top: 0; }
&:last-child { border-bottom: 0; }
.accordion-button {
// stylelint-disable selector-max-class
> .accordion-header .accordion-button {
&,
&.collapsed {
@include border-radius(0);
}
}
// stylelint-enable selector-max-class
> .accordion-collapse {
@include border-radius(0);
}
}
}
@if $enable-dark-mode {
@include color-mode(dark) {
.accordion-button::after {
--#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon-dark)};
--#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon-dark)};
}
}
}

View file

@ -3,11 +3,25 @@
//
.alert {
// scss-docs-start alert-css-vars
--#{$prefix}alert-bg: transparent;
--#{$prefix}alert-padding-x: #{$alert-padding-x};
--#{$prefix}alert-padding-y: #{$alert-padding-y};
--#{$prefix}alert-margin-bottom: #{$alert-margin-bottom};
--#{$prefix}alert-color: inherit;
--#{$prefix}alert-border-color: transparent;
--#{$prefix}alert-border: #{$alert-border-width} solid var(--#{$prefix}alert-border-color);
--#{$prefix}alert-border-radius: #{$alert-border-radius};
--#{$prefix}alert-link-color: inherit;
// scss-docs-end alert-css-vars
position: relative;
padding: $alert-padding-y $alert-padding-x;
margin-bottom: $alert-margin-bottom;
border: $alert-border-width solid transparent;
@include border-radius($alert-border-radius);
padding: var(--#{$prefix}alert-padding-y) var(--#{$prefix}alert-padding-x);
margin-bottom: var(--#{$prefix}alert-margin-bottom);
color: var(--#{$prefix}alert-color);
background-color: var(--#{$prefix}alert-bg);
border: var(--#{$prefix}alert-border);
@include border-radius(var(--#{$prefix}alert-border-radius));
}
// Headings for larger alerts
@ -19,6 +33,7 @@
// Provide class for links that match alerts
.alert-link {
font-weight: $alert-link-font-weight;
color: var(--#{$prefix}alert-link-color);
}
@ -41,17 +56,13 @@
// scss-docs-start alert-modifiers
// Generate contextual modifier classes for colorizing the alert.
@each $state, $value in $theme-colors {
$alert-background: shift-color($value, $alert-bg-scale);
$alert-border: shift-color($value, $alert-border-scale);
$alert-color: shift-color($value, $alert-color-scale);
@if (contrast-ratio($alert-background, $alert-color) < $min-contrast-ratio) {
$alert-color: mix($value, color-contrast($alert-background), abs($alert-color-scale));
}
// Generate contextual modifier classes for colorizing the alert
@each $state in map-keys($theme-colors) {
.alert-#{$state} {
@include alert-variant($alert-background, $alert-border, $alert-color);
--#{$prefix}alert-color: var(--#{$prefix}#{$state}-text-emphasis);
--#{$prefix}alert-bg: var(--#{$prefix}#{$state}-bg-subtle);
--#{$prefix}alert-border-color: var(--#{$prefix}#{$state}-border-subtle);
--#{$prefix}alert-link-color: var(--#{$prefix}#{$state}-text-emphasis);
}
}
// scss-docs-end alert-modifiers

View file

@ -4,16 +4,25 @@
// `background-color`.
.badge {
// scss-docs-start badge-css-vars
--#{$prefix}badge-padding-x: #{$badge-padding-x};
--#{$prefix}badge-padding-y: #{$badge-padding-y};
@include rfs($badge-font-size, --#{$prefix}badge-font-size);
--#{$prefix}badge-font-weight: #{$badge-font-weight};
--#{$prefix}badge-color: #{$badge-color};
--#{$prefix}badge-border-radius: #{$badge-border-radius};
// scss-docs-end badge-css-vars
display: inline-block;
padding: $badge-padding-y $badge-padding-x;
@include font-size($badge-font-size);
font-weight: $badge-font-weight;
padding: var(--#{$prefix}badge-padding-y) var(--#{$prefix}badge-padding-x);
@include font-size(var(--#{$prefix}badge-font-size));
font-weight: var(--#{$prefix}badge-font-weight);
line-height: 1;
color: $badge-color;
color: var(--#{$prefix}badge-color);
text-align: center;
white-space: nowrap;
vertical-align: baseline;
@include border-radius($badge-border-radius);
@include border-radius(var(--#{$prefix}badge-border-radius));
@include gradient-bg();
// Empty badges collapse automatically

View file

@ -1,28 +1,40 @@
.breadcrumb {
// scss-docs-start breadcrumb-css-vars
--#{$prefix}breadcrumb-padding-x: #{$breadcrumb-padding-x};
--#{$prefix}breadcrumb-padding-y: #{$breadcrumb-padding-y};
--#{$prefix}breadcrumb-margin-bottom: #{$breadcrumb-margin-bottom};
@include rfs($breadcrumb-font-size, --#{$prefix}breadcrumb-font-size);
--#{$prefix}breadcrumb-bg: #{$breadcrumb-bg};
--#{$prefix}breadcrumb-border-radius: #{$breadcrumb-border-radius};
--#{$prefix}breadcrumb-divider-color: #{$breadcrumb-divider-color};
--#{$prefix}breadcrumb-item-padding-x: #{$breadcrumb-item-padding-x};
--#{$prefix}breadcrumb-item-active-color: #{$breadcrumb-active-color};
// scss-docs-end breadcrumb-css-vars
display: flex;
flex-wrap: wrap;
padding: $breadcrumb-padding-y $breadcrumb-padding-x;
margin-bottom: $breadcrumb-margin-bottom;
@include font-size($breadcrumb-font-size);
padding: var(--#{$prefix}breadcrumb-padding-y) var(--#{$prefix}breadcrumb-padding-x);
margin-bottom: var(--#{$prefix}breadcrumb-margin-bottom);
@include font-size(var(--#{$prefix}breadcrumb-font-size));
list-style: none;
background-color: $breadcrumb-bg;
@include border-radius($breadcrumb-border-radius);
background-color: var(--#{$prefix}breadcrumb-bg);
@include border-radius(var(--#{$prefix}breadcrumb-border-radius));
}
.breadcrumb-item {
// The separator between breadcrumbs (by default, a forward-slash: "/")
+ .breadcrumb-item {
padding-left: $breadcrumb-item-padding-x;
padding-left: var(--#{$prefix}breadcrumb-item-padding-x);
&::before {
float: left; // Suppress inline spacings and underlining of the separator
padding-right: $breadcrumb-item-padding-x;
color: $breadcrumb-divider-color;
content: var(--#{$variable-prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{"/* rtl:"} var(--#{$variable-prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{"*/"};
padding-right: var(--#{$prefix}breadcrumb-item-padding-x);
color: var(--#{$prefix}breadcrumb-divider-color);
content: var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{"/* rtl:"} var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{"*/"};
}
}
&.active {
color: $breadcrumb-active-color;
color: var(--#{$prefix}breadcrumb-item-active-color);
}
}

View file

@ -34,14 +34,17 @@
}
.btn-group {
@include border-radius($btn-border-radius);
// Prevent double borders when buttons are next to each other
> .btn:not(:first-child),
> :not(.btn-check:first-child) + .btn,
> .btn-group:not(:first-child) {
margin-left: -$btn-border-width;
margin-left: calc(#{$btn-border-width} * -1); // stylelint-disable-line function-disallowed-list
}
// Reset rounded corners
> .btn:not(:last-child):not(.dropdown-toggle),
> .btn.dropdown-toggle-split:first-child,
> .btn-group:not(:last-child) > .btn {
@include border-end-radius(0);
}
@ -123,7 +126,7 @@
> .btn:not(:first-child),
> .btn-group:not(:first-child) {
margin-top: -$btn-border-width;
margin-top: calc(#{$btn-border-width} * -1); // stylelint-disable-line function-disallowed-list
}
// Reset rounded corners

View file

@ -3,49 +3,121 @@
//
.btn {
// scss-docs-start btn-css-vars
--#{$prefix}btn-padding-x: #{$btn-padding-x};
--#{$prefix}btn-padding-y: #{$btn-padding-y};
--#{$prefix}btn-font-family: #{$btn-font-family};
@include rfs($btn-font-size, --#{$prefix}btn-font-size);
--#{$prefix}btn-font-weight: #{$btn-font-weight};
--#{$prefix}btn-line-height: #{$btn-line-height};
--#{$prefix}btn-color: #{$btn-color};
--#{$prefix}btn-bg: transparent;
--#{$prefix}btn-border-width: #{$btn-border-width};
--#{$prefix}btn-border-color: transparent;
--#{$prefix}btn-border-radius: #{$btn-border-radius};
--#{$prefix}btn-hover-border-color: transparent;
--#{$prefix}btn-box-shadow: #{$btn-box-shadow};
--#{$prefix}btn-disabled-opacity: #{$btn-disabled-opacity};
--#{$prefix}btn-focus-box-shadow: 0 0 0 #{$btn-focus-width} rgba(var(--#{$prefix}btn-focus-shadow-rgb), .5);
// scss-docs-end btn-css-vars
display: inline-block;
font-family: $btn-font-family;
font-weight: $btn-font-weight;
line-height: $btn-line-height;
color: $body-color;
padding: var(--#{$prefix}btn-padding-y) var(--#{$prefix}btn-padding-x);
font-family: var(--#{$prefix}btn-font-family);
@include font-size(var(--#{$prefix}btn-font-size));
font-weight: var(--#{$prefix}btn-font-weight);
line-height: var(--#{$prefix}btn-line-height);
color: var(--#{$prefix}btn-color);
text-align: center;
text-decoration: if($link-decoration == none, null, none);
white-space: $btn-white-space;
vertical-align: middle;
cursor: if($enable-button-pointers, pointer, null);
user-select: none;
background-color: transparent;
border: $btn-border-width solid transparent;
@include button-size($btn-padding-y, $btn-padding-x, $btn-font-size, $btn-border-radius);
border: var(--#{$prefix}btn-border-width) solid var(--#{$prefix}btn-border-color);
@include border-radius(var(--#{$prefix}btn-border-radius));
@include gradient-bg(var(--#{$prefix}btn-bg));
@include box-shadow(var(--#{$prefix}btn-box-shadow));
@include transition($btn-transition);
&:hover {
color: $body-color;
color: var(--#{$prefix}btn-hover-color);
text-decoration: if($link-hover-decoration == underline, none, null);
background-color: var(--#{$prefix}btn-hover-bg);
border-color: var(--#{$prefix}btn-hover-border-color);
}
.btn-check:focus + &,
&:focus {
.btn-check + &:hover {
// override for the checkbox/radio buttons
color: var(--#{$prefix}btn-color);
background-color: var(--#{$prefix}btn-bg);
border-color: var(--#{$prefix}btn-border-color);
}
&:focus-visible {
color: var(--#{$prefix}btn-hover-color);
@include gradient-bg(var(--#{$prefix}btn-hover-bg));
border-color: var(--#{$prefix}btn-hover-border-color);
outline: 0;
box-shadow: $btn-focus-box-shadow;
// Avoid using mixin so we can pass custom focus shadow properly
@if $enable-shadows {
box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow);
} @else {
box-shadow: var(--#{$prefix}btn-focus-box-shadow);
}
}
.btn-check:focus-visible + & {
border-color: var(--#{$prefix}btn-hover-border-color);
outline: 0;
// Avoid using mixin so we can pass custom focus shadow properly
@if $enable-shadows {
box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow);
} @else {
box-shadow: var(--#{$prefix}btn-focus-box-shadow);
}
}
.btn-check:checked + &,
.btn-check:active + &,
&:active,
&.active {
@include box-shadow($btn-active-box-shadow);
:not(.btn-check) + &:active,
&:first-child:active,
&.active,
&.show {
color: var(--#{$prefix}btn-active-color);
background-color: var(--#{$prefix}btn-active-bg);
// Remove CSS gradients if they're enabled
background-image: if($enable-gradients, none, null);
border-color: var(--#{$prefix}btn-active-border-color);
@include box-shadow(var(--#{$prefix}btn-active-shadow));
&:focus {
@include box-shadow($btn-focus-box-shadow, $btn-active-box-shadow);
&:focus-visible {
// Avoid using mixin so we can pass custom focus shadow properly
@if $enable-shadows {
box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow);
} @else {
box-shadow: var(--#{$prefix}btn-focus-box-shadow);
}
}
}
.btn-check:checked:focus-visible + & {
// Avoid using mixin so we can pass custom focus shadow properly
@if $enable-shadows {
box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow);
} @else {
box-shadow: var(--#{$prefix}btn-focus-box-shadow);
}
}
&:disabled,
&.disabled,
fieldset:disabled & {
color: var(--#{$prefix}btn-disabled-color);
pointer-events: none;
opacity: $btn-disabled-opacity;
background-color: var(--#{$prefix}btn-disabled-bg);
background-image: if($enable-gradients, none, null);
border-color: var(--#{$prefix}btn-disabled-border-color);
opacity: var(--#{$prefix}btn-disabled-opacity);
@include box-shadow(none);
}
}
@ -58,7 +130,27 @@
// scss-docs-start btn-variant-loops
@each $color, $value in $theme-colors {
.btn-#{$color} {
@include button-variant($value, $value);
@if $color == "light" {
@include button-variant(
$value,
$value,
$hover-background: shade-color($value, $btn-hover-bg-shade-amount),
$hover-border: shade-color($value, $btn-hover-border-shade-amount),
$active-background: shade-color($value, $btn-active-bg-shade-amount),
$active-border: shade-color($value, $btn-active-border-shade-amount)
);
} @else if $color == "dark" {
@include button-variant(
$value,
$value,
$hover-background: tint-color($value, $btn-hover-bg-tint-amount),
$hover-border: tint-color($value, $btn-hover-border-tint-amount),
$active-background: tint-color($value, $btn-active-bg-tint-amount),
$active-border: tint-color($value, $btn-active-border-tint-amount)
);
} @else {
@include button-variant($value, $value);
}
}
}
@ -76,22 +168,35 @@
// Make a button look and behave like a link
.btn-link {
font-weight: $font-weight-normal;
color: $btn-link-color;
--#{$prefix}btn-font-weight: #{$font-weight-normal};
--#{$prefix}btn-color: #{$btn-link-color};
--#{$prefix}btn-bg: transparent;
--#{$prefix}btn-border-color: transparent;
--#{$prefix}btn-hover-color: #{$btn-link-hover-color};
--#{$prefix}btn-hover-border-color: transparent;
--#{$prefix}btn-active-color: #{$btn-link-hover-color};
--#{$prefix}btn-active-border-color: transparent;
--#{$prefix}btn-disabled-color: #{$btn-link-disabled-color};
--#{$prefix}btn-disabled-border-color: transparent;
--#{$prefix}btn-box-shadow: 0 0 0 #000; // Can't use `none` as keyword negates all values when used with multiple shadows
--#{$prefix}btn-focus-shadow-rgb: #{$btn-link-focus-shadow-rgb};
text-decoration: $link-decoration;
@if $enable-gradients {
background-image: none;
}
&:hover,
&:focus-visible {
text-decoration: $link-hover-decoration;
}
&:focus-visible {
color: var(--#{$prefix}btn-color);
}
&:hover {
color: $btn-link-hover-color;
text-decoration: $link-hover-decoration;
}
&:focus {
text-decoration: $link-hover-decoration;
}
&:disabled,
&.disabled {
color: $btn-link-disabled-color;
color: var(--#{$prefix}btn-hover-color);
}
// No need for an active state here

View file

@ -3,17 +3,40 @@
//
.card {
// scss-docs-start card-css-vars
--#{$prefix}card-spacer-y: #{$card-spacer-y};
--#{$prefix}card-spacer-x: #{$card-spacer-x};
--#{$prefix}card-title-spacer-y: #{$card-title-spacer-y};
--#{$prefix}card-title-color: #{$card-title-color};
--#{$prefix}card-subtitle-color: #{$card-subtitle-color};
--#{$prefix}card-border-width: #{$card-border-width};
--#{$prefix}card-border-color: #{$card-border-color};
--#{$prefix}card-border-radius: #{$card-border-radius};
--#{$prefix}card-box-shadow: #{$card-box-shadow};
--#{$prefix}card-inner-border-radius: #{$card-inner-border-radius};
--#{$prefix}card-cap-padding-y: #{$card-cap-padding-y};
--#{$prefix}card-cap-padding-x: #{$card-cap-padding-x};
--#{$prefix}card-cap-bg: #{$card-cap-bg};
--#{$prefix}card-cap-color: #{$card-cap-color};
--#{$prefix}card-height: #{$card-height};
--#{$prefix}card-color: #{$card-color};
--#{$prefix}card-bg: #{$card-bg};
--#{$prefix}card-img-overlay-padding: #{$card-img-overlay-padding};
--#{$prefix}card-group-margin: #{$card-group-margin};
// scss-docs-end card-css-vars
position: relative;
display: flex;
flex-direction: column;
min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106
height: $card-height;
height: var(--#{$prefix}card-height);
color: var(--#{$prefix}body-color);
word-wrap: break-word;
background-color: $card-bg;
background-color: var(--#{$prefix}card-bg);
background-clip: border-box;
border: $card-border-width solid $card-border-color;
@include border-radius($card-border-radius);
@include box-shadow($card-box-shadow);
border: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);
@include border-radius(var(--#{$prefix}card-border-radius));
@include box-shadow(var(--#{$prefix}card-box-shadow));
> hr {
margin-right: 0;
@ -26,12 +49,12 @@
&:first-child {
border-top-width: 0;
@include border-top-radius($card-inner-border-radius);
@include border-top-radius(var(--#{$prefix}card-inner-border-radius));
}
&:last-child {
border-bottom-width: 0;
@include border-bottom-radius($card-inner-border-radius);
@include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));
}
}
@ -47,17 +70,19 @@
// Enable `flex-grow: 1` for decks and groups so that card blocks take up
// as much space as possible, ensuring footers are aligned to the bottom.
flex: 1 1 auto;
padding: $card-spacer-y $card-spacer-x;
color: $card-color;
padding: var(--#{$prefix}card-spacer-y) var(--#{$prefix}card-spacer-x);
color: var(--#{$prefix}card-color);
}
.card-title {
margin-bottom: $card-title-spacer-y;
margin-bottom: var(--#{$prefix}card-title-spacer-y);
color: var(--#{$prefix}card-title-color);
}
.card-subtitle {
margin-top: -$card-title-spacer-y * .5;
margin-top: calc(-.5 * var(--#{$prefix}card-title-spacer-y)); // stylelint-disable-line function-disallowed-list
margin-bottom: 0;
color: var(--#{$prefix}card-subtitle-color);
}
.card-text:last-child {
@ -70,7 +95,7 @@
}
+ .card-link {
margin-left: $card-spacer-x;
margin-left: var(--#{$prefix}card-spacer-x);
}
}
@ -79,25 +104,25 @@
//
.card-header {
padding: $card-cap-padding-y $card-cap-padding-x;
padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x);
margin-bottom: 0; // Removes the default margin-bottom of <hN>
color: $card-cap-color;
background-color: $card-cap-bg;
border-bottom: $card-border-width solid $card-border-color;
color: var(--#{$prefix}card-cap-color);
background-color: var(--#{$prefix}card-cap-bg);
border-bottom: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);
&:first-child {
@include border-radius($card-inner-border-radius $card-inner-border-radius 0 0);
@include border-radius(var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius) 0 0);
}
}
.card-footer {
padding: $card-cap-padding-y $card-cap-padding-x;
color: $card-cap-color;
background-color: $card-cap-bg;
border-top: $card-border-width solid $card-border-color;
padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x);
color: var(--#{$prefix}card-cap-color);
background-color: var(--#{$prefix}card-cap-bg);
border-top: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color);
&:last-child {
@include border-radius(0 0 $card-inner-border-radius $card-inner-border-radius);
@include border-radius(0 0 var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius));
}
}
@ -107,22 +132,20 @@
//
.card-header-tabs {
margin-right: -$card-cap-padding-x * .5;
margin-bottom: -$card-cap-padding-y;
margin-left: -$card-cap-padding-x * .5;
margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
margin-bottom: calc(-1 * var(--#{$prefix}card-cap-padding-y)); // stylelint-disable-line function-disallowed-list
margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
border-bottom: 0;
@if $nav-tabs-link-active-bg != $card-bg {
.nav-link.active {
background-color: $card-bg;
border-bottom-color: $card-bg;
}
.nav-link.active {
background-color: var(--#{$prefix}card-bg);
border-bottom-color: var(--#{$prefix}card-bg);
}
}
.card-header-pills {
margin-right: -$card-cap-padding-x * .5;
margin-left: -$card-cap-padding-x * .5;
margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
}
// Card image
@ -132,8 +155,8 @@
right: 0;
bottom: 0;
left: 0;
padding: $card-img-overlay-padding;
@include border-radius($card-inner-border-radius);
padding: var(--#{$prefix}card-img-overlay-padding);
@include border-radius(var(--#{$prefix}card-inner-border-radius));
}
.card-img,
@ -144,12 +167,12 @@
.card-img,
.card-img-top {
@include border-top-radius($card-inner-border-radius);
@include border-top-radius(var(--#{$prefix}card-inner-border-radius));
}
.card-img,
.card-img-bottom {
@include border-bottom-radius($card-inner-border-radius);
@include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));
}
@ -161,7 +184,7 @@
// The child selector allows nested `.card` within `.card-group`
// to display properly.
> .card {
margin-bottom: $card-group-margin;
margin-bottom: var(--#{$prefix}card-group-margin);
}
@include media-breakpoint-up(sm) {

View file

@ -42,7 +42,6 @@
display: block;
}
/* rtl:begin:ignore */
.carousel-item-next:not(.carousel-item-start),
.active.carousel-item-end {
transform: translateX(100%);
@ -53,8 +52,6 @@
transform: translateX(-100%);
}
/* rtl:end:ignore */
//
// Alternate transitions
@ -135,19 +132,11 @@
background-size: 100% 100%;
}
/* rtl:options: {
"autoRename": true,
"stringMap":[ {
"name" : "prev-next",
"search" : "prev",
"replace" : "next"
} ]
} */
.carousel-control-prev-icon {
background-image: escape-svg($carousel-control-prev-icon-bg);
background-image: escape-svg($carousel-control-prev-icon-bg) #{"/*rtl:" + escape-svg($carousel-control-next-icon-bg) + "*/"};
}
.carousel-control-next-icon {
background-image: escape-svg($carousel-control-next-icon-bg);
background-image: escape-svg($carousel-control-next-icon-bg) #{"/*rtl:" + escape-svg($carousel-control-prev-icon-bg) + "*/"};
}
// Optional indicator pips/controls
@ -168,7 +157,6 @@
margin-right: $carousel-control-width;
margin-bottom: 1rem;
margin-left: $carousel-control-width;
list-style: none;
[data-bs-target] {
box-sizing: content-box;
@ -213,7 +201,7 @@
// Dark mode carousel
.carousel-dark {
@mixin carousel-dark() {
.carousel-control-prev-icon,
.carousel-control-next-icon {
filter: $carousel-dark-control-icon-filter;
@ -227,3 +215,22 @@
color: $carousel-dark-caption-color;
}
}
.carousel-dark {
@include carousel-dark();
}
@if $enable-dark-mode {
@include color-mode(dark) {
@if $color-mode-type == "media-query" {
.carousel {
@include carousel-dark();
}
} @else {
.carousel,
&.carousel {
@include carousel-dark();
}
}
}
}

View file

@ -1,40 +1,63 @@
// transparent background and border properties included for button version.
// Transparent background and border properties included for button version.
// iOS requires the button element instead of an anchor tag.
// If you want the anchor version, it requires `href="#"`.
// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
.btn-close {
// scss-docs-start close-css-vars
--#{$prefix}btn-close-color: #{$btn-close-color};
--#{$prefix}btn-close-bg: #{ escape-svg($btn-close-bg) };
--#{$prefix}btn-close-opacity: #{$btn-close-opacity};
--#{$prefix}btn-close-hover-opacity: #{$btn-close-hover-opacity};
--#{$prefix}btn-close-focus-shadow: #{$btn-close-focus-shadow};
--#{$prefix}btn-close-focus-opacity: #{$btn-close-focus-opacity};
--#{$prefix}btn-close-disabled-opacity: #{$btn-close-disabled-opacity};
--#{$prefix}btn-close-white-filter: #{$btn-close-white-filter};
// scss-docs-end close-css-vars
box-sizing: content-box;
width: $btn-close-width;
height: $btn-close-height;
padding: $btn-close-padding-y $btn-close-padding-x;
color: $btn-close-color;
background: transparent escape-svg($btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements
color: var(--#{$prefix}btn-close-color);
background: transparent var(--#{$prefix}btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements
border: 0; // for button elements
@include border-radius();
opacity: $btn-close-opacity;
opacity: var(--#{$prefix}btn-close-opacity);
// Override <a>'s hover style
&:hover {
color: $btn-close-color;
color: var(--#{$prefix}btn-close-color);
text-decoration: none;
opacity: $btn-close-hover-opacity;
opacity: var(--#{$prefix}btn-close-hover-opacity);
}
&:focus {
outline: 0;
box-shadow: $btn-close-focus-shadow;
opacity: $btn-close-focus-opacity;
box-shadow: var(--#{$prefix}btn-close-focus-shadow);
opacity: var(--#{$prefix}btn-close-focus-opacity);
}
&:disabled,
&.disabled {
pointer-events: none;
user-select: none;
opacity: $btn-close-disabled-opacity;
opacity: var(--#{$prefix}btn-close-disabled-opacity);
}
}
.btn-close-white {
filter: $btn-close-white-filter;
@mixin btn-close-white() {
filter: var(--#{$prefix}btn-close-white-filter);
}
.btn-close-white {
@include btn-close-white();
}
@if $enable-dark-mode {
@include color-mode(dark) {
.btn-close {
@include btn-close-white();
}
}
}

View file

@ -2,7 +2,7 @@
//
// Set the container width, and override it for fixed navbars in media queries.
@if $enable-grid-classes {
@if $enable-container-classes {
// Single container class with breakpoint max-widths
.container,
// 100% wide container at all breakpoints

View file

@ -2,7 +2,9 @@
.dropup,
.dropend,
.dropdown,
.dropstart {
.dropstart,
.dropup-center,
.dropdown-center {
position: relative;
}
@ -15,26 +17,67 @@
// The dropdown menu
.dropdown-menu {
// scss-docs-start dropdown-css-vars
--#{$prefix}dropdown-zindex: #{$zindex-dropdown};
--#{$prefix}dropdown-min-width: #{$dropdown-min-width};
--#{$prefix}dropdown-padding-x: #{$dropdown-padding-x};
--#{$prefix}dropdown-padding-y: #{$dropdown-padding-y};
--#{$prefix}dropdown-spacer: #{$dropdown-spacer};
@include rfs($dropdown-font-size, --#{$prefix}dropdown-font-size);
--#{$prefix}dropdown-color: #{$dropdown-color};
--#{$prefix}dropdown-bg: #{$dropdown-bg};
--#{$prefix}dropdown-border-color: #{$dropdown-border-color};
--#{$prefix}dropdown-border-radius: #{$dropdown-border-radius};
--#{$prefix}dropdown-border-width: #{$dropdown-border-width};
--#{$prefix}dropdown-inner-border-radius: #{$dropdown-inner-border-radius};
--#{$prefix}dropdown-divider-bg: #{$dropdown-divider-bg};
--#{$prefix}dropdown-divider-margin-y: #{$dropdown-divider-margin-y};
--#{$prefix}dropdown-box-shadow: #{$dropdown-box-shadow};
--#{$prefix}dropdown-link-color: #{$dropdown-link-color};
--#{$prefix}dropdown-link-hover-color: #{$dropdown-link-hover-color};
--#{$prefix}dropdown-link-hover-bg: #{$dropdown-link-hover-bg};
--#{$prefix}dropdown-link-active-color: #{$dropdown-link-active-color};
--#{$prefix}dropdown-link-active-bg: #{$dropdown-link-active-bg};
--#{$prefix}dropdown-link-disabled-color: #{$dropdown-link-disabled-color};
--#{$prefix}dropdown-item-padding-x: #{$dropdown-item-padding-x};
--#{$prefix}dropdown-item-padding-y: #{$dropdown-item-padding-y};
--#{$prefix}dropdown-header-color: #{$dropdown-header-color};
--#{$prefix}dropdown-header-padding-x: #{$dropdown-header-padding-x};
--#{$prefix}dropdown-header-padding-y: #{$dropdown-header-padding-y};
// scss-docs-end dropdown-css-vars
position: absolute;
z-index: $zindex-dropdown;
z-index: var(--#{$prefix}dropdown-zindex);
display: none; // none by default, but block on "open" of the menu
min-width: $dropdown-min-width;
padding: $dropdown-padding-y $dropdown-padding-x;
min-width: var(--#{$prefix}dropdown-min-width);
padding: var(--#{$prefix}dropdown-padding-y) var(--#{$prefix}dropdown-padding-x);
margin: 0; // Override default margin of ul
@include font-size($dropdown-font-size);
color: $dropdown-color;
@include font-size(var(--#{$prefix}dropdown-font-size));
color: var(--#{$prefix}dropdown-color);
text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
list-style: none;
background-color: $dropdown-bg;
background-color: var(--#{$prefix}dropdown-bg);
background-clip: padding-box;
border: $dropdown-border-width solid $dropdown-border-color;
@include border-radius($dropdown-border-radius);
@include box-shadow($dropdown-box-shadow);
border: var(--#{$prefix}dropdown-border-width) solid var(--#{$prefix}dropdown-border-color);
@include border-radius(var(--#{$prefix}dropdown-border-radius));
@include box-shadow(var(--#{$prefix}dropdown-box-shadow));
&[data-bs-popper] {
top: 100%;
left: 0;
margin-top: $dropdown-spacer;
margin-top: var(--#{$prefix}dropdown-spacer);
}
@if $dropdown-padding-y == 0 {
> .dropdown-item:first-child,
> li:first-child .dropdown-item {
@include border-top-radius(var(--#{$prefix}dropdown-inner-border-radius));
}
> .dropdown-item:last-child,
> li:last-child .dropdown-item {
@include border-bottom-radius(var(--#{$prefix}dropdown-inner-border-radius));
}
}
}
@ -74,7 +117,7 @@
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: $dropdown-spacer;
margin-bottom: var(--#{$prefix}dropdown-spacer);
}
.dropdown-toggle {
@ -88,7 +131,7 @@
right: auto;
left: 100%;
margin-top: 0;
margin-left: $dropdown-spacer;
margin-left: var(--#{$prefix}dropdown-spacer);
}
.dropdown-toggle {
@ -105,7 +148,7 @@
right: 100%;
left: auto;
margin-top: 0;
margin-right: $dropdown-spacer;
margin-right: var(--#{$prefix}dropdown-spacer);
}
.dropdown-toggle {
@ -120,9 +163,10 @@
// Dividers (basically an `<hr>`) within the dropdown
.dropdown-divider {
height: 0;
margin: $dropdown-divider-margin-y 0;
margin: var(--#{$prefix}dropdown-divider-margin-y) 0;
overflow: hidden;
border-top: 1px solid $dropdown-divider-bg;
border-top: 1px solid var(--#{$prefix}dropdown-divider-bg);
opacity: 1; // Revisit in v6 to de-dupe styles that conflict with <hr> element
}
// Links, buttons, and more within the dropdown menu
@ -131,45 +175,34 @@
.dropdown-item {
display: block;
width: 100%; // For `<button>`s
padding: $dropdown-item-padding-y $dropdown-item-padding-x;
padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x);
clear: both;
font-weight: $font-weight-normal;
color: $dropdown-link-color;
color: var(--#{$prefix}dropdown-link-color);
text-align: inherit; // For `<button>`s
text-decoration: if($link-decoration == none, null, none);
white-space: nowrap; // prevent links from randomly breaking onto new lines
background-color: transparent; // For `<button>`s
border: 0; // For `<button>`s
// Prevent dropdown overflow if there's no padding
// See https://github.com/twbs/bootstrap/pull/27703
@if $dropdown-padding-y == 0 {
&:first-child {
@include border-top-radius($dropdown-inner-border-radius);
}
&:last-child {
@include border-bottom-radius($dropdown-inner-border-radius);
}
}
@include border-radius(var(--#{$prefix}dropdown-item-border-radius, 0));
&:hover,
&:focus {
color: $dropdown-link-hover-color;
color: var(--#{$prefix}dropdown-link-hover-color);
text-decoration: if($link-hover-decoration == underline, none, null);
@include gradient-bg($dropdown-link-hover-bg);
@include gradient-bg(var(--#{$prefix}dropdown-link-hover-bg));
}
&.active,
&:active {
color: $dropdown-link-active-color;
color: var(--#{$prefix}dropdown-link-active-color);
text-decoration: none;
@include gradient-bg($dropdown-link-active-bg);
@include gradient-bg(var(--#{$prefix}dropdown-link-active-bg));
}
&.disabled,
&:disabled {
color: $dropdown-link-disabled-color;
color: var(--#{$prefix}dropdown-link-disabled-color);
pointer-events: none;
background-color: transparent;
// Remove CSS gradients if they're enabled
@ -184,57 +217,34 @@
// Dropdown section headers
.dropdown-header {
display: block;
padding: $dropdown-header-padding;
padding: var(--#{$prefix}dropdown-header-padding-y) var(--#{$prefix}dropdown-header-padding-x);
margin-bottom: 0; // for use with heading elements
@include font-size($font-size-sm);
color: $dropdown-header-color;
color: var(--#{$prefix}dropdown-header-color);
white-space: nowrap; // as with > li > a
}
// Dropdown text
.dropdown-item-text {
display: block;
padding: $dropdown-item-padding-y $dropdown-item-padding-x;
color: $dropdown-link-color;
padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x);
color: var(--#{$prefix}dropdown-link-color);
}
// Dark dropdowns
.dropdown-menu-dark {
color: $dropdown-dark-color;
background-color: $dropdown-dark-bg;
border-color: $dropdown-dark-border-color;
@include box-shadow($dropdown-dark-box-shadow);
.dropdown-item {
color: $dropdown-dark-link-color;
&:hover,
&:focus {
color: $dropdown-dark-link-hover-color;
@include gradient-bg($dropdown-dark-link-hover-bg);
}
&.active,
&:active {
color: $dropdown-dark-link-active-color;
@include gradient-bg($dropdown-dark-link-active-bg);
}
&.disabled,
&:disabled {
color: $dropdown-dark-link-disabled-color;
}
}
.dropdown-divider {
border-color: $dropdown-dark-divider-bg;
}
.dropdown-item-text {
color: $dropdown-dark-link-color;
}
.dropdown-header {
color: $dropdown-dark-header-color;
}
// scss-docs-start dropdown-dark-css-vars
--#{$prefix}dropdown-color: #{$dropdown-dark-color};
--#{$prefix}dropdown-bg: #{$dropdown-dark-bg};
--#{$prefix}dropdown-border-color: #{$dropdown-dark-border-color};
--#{$prefix}dropdown-box-shadow: #{$dropdown-dark-box-shadow};
--#{$prefix}dropdown-link-color: #{$dropdown-dark-link-color};
--#{$prefix}dropdown-link-hover-color: #{$dropdown-dark-link-hover-color};
--#{$prefix}dropdown-divider-bg: #{$dropdown-dark-divider-bg};
--#{$prefix}dropdown-link-hover-bg: #{$dropdown-dark-link-hover-bg};
--#{$prefix}dropdown-link-active-color: #{$dropdown-dark-link-active-color};
--#{$prefix}dropdown-link-active-bg: #{$dropdown-dark-link-active-bg};
--#{$prefix}dropdown-link-disabled-color: #{$dropdown-dark-link-disabled-color};
--#{$prefix}dropdown-header-color: #{$dropdown-dark-header-color};
// scss-docs-end dropdown-dark-css-vars
}

View file

@ -40,11 +40,11 @@
// stylelint-disable scss/dollar-variable-pattern
@function rgba-css-var($identifier, $target) {
@if $identifier == "body" and $target == "bg" {
@return rgba(var(--#{$variable-prefix}#{$identifier}-bg-rgb), var(--#{$variable-prefix}#{$target}-opacity));
@return rgba(var(--#{$prefix}#{$identifier}-bg-rgb), var(--#{$prefix}#{$target}-opacity));
} @if $identifier == "body" and $target == "text" {
@return rgba(var(--#{$variable-prefix}#{$identifier}-color-rgb), var(--#{$variable-prefix}#{$target}-opacity));
@return rgba(var(--#{$prefix}#{$identifier}-color-rgb), var(--#{$prefix}#{$target}-opacity));
} @else {
@return rgba(var(--#{$variable-prefix}#{$identifier}-rgb), var(--#{$variable-prefix}#{$target}-opacity));
@return rgba(var(--#{$prefix}#{$identifier}-rgb), var(--#{$prefix}#{$target}-opacity));
}
}
@ -68,7 +68,7 @@
@function varify($list) {
$result: null;
@each $entry in $list {
$result: append($result, var(--#{$variable-prefix}#{$entry}), space);
$result: append($result, var(--#{$prefix}#{$entry}), space);
}
@return $result;
}
@ -109,7 +109,7 @@
// Replace `$search` with `$replace` in `$string`
// Used on our SVG icon backgrounds for custom forms.
//
// @author Hugo Giraudel
// @author Kitty Giraudel
// @param {String} $string - Initial string
// @param {String} $search - Substring to replace
// @param {String} $replace ('') - New value
@ -177,9 +177,9 @@ $_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003
@return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05));
}
// Return WCAG2.0 relative luminance
// See https://www.w3.org/WAI/GL/wiki/Relative_luminance
// See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
// Return WCAG2.1 relative luminance
// See https://www.w3.org/TR/WCAG/#dfn-relative-luminance
// See https://www.w3.org/TR/WCAG/#dfn-contrast-ratio
@function luminance($color) {
$rgb: (
"r": red($color),
@ -188,7 +188,7 @@ $_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003
);
@each $name, $value in $rgb {
$value: if(divide($value, 255) < .03928, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1));
$value: if(divide($value, 255) < .04045, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1));
$rgb: map-merge($rgb, ($name: $value));
}
@ -198,7 +198,7 @@ $_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003
// Return opaque color
// opaque(#fff, rgba(0, 0, 0, .5)) => #808080
@function opaque($background, $foreground) {
@return mix(rgba($foreground, 1), $background, opacity($foreground) * 100);
@return mix(rgba($foreground, 1), $background, opacity($foreground) * 100%);
}
// scss-docs-start color-functions

View file

@ -2,6 +2,12 @@
//
// Rows contain your columns.
:root {
@each $name, $value in $grid-breakpoints {
--#{$prefix}breakpoint-#{$name}: #{$value};
}
}
@if $enable-grid-classes {
.row {
@include make-row();
@ -15,9 +21,9 @@
@if $enable-cssgrid {
.grid {
display: grid;
grid-template-rows: repeat(var(--#{$variable-prefix}rows, 1), 1fr);
grid-template-columns: repeat(var(--#{$variable-prefix}columns, #{$grid-columns}), 1fr);
gap: var(--#{$variable-prefix}gap, #{$grid-gutter-width});
grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr);
grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr);
gap: var(--#{$prefix}gap, #{$grid-gutter-width});
@include make-cssgrid();
}

View file

@ -1,5 +1,8 @@
@import "helpers/clearfix";
@import "helpers/color-bg";
@import "helpers/colored-links";
@import "helpers/focus-ring";
@import "helpers/icon-link";
@import "helpers/ratio";
@import "helpers/position";
@import "helpers/stacks";

View file

@ -3,27 +3,46 @@
// Easily usable on <ul>, <ol>, or <div>.
.list-group {
// scss-docs-start list-group-css-vars
--#{$prefix}list-group-color: #{$list-group-color};
--#{$prefix}list-group-bg: #{$list-group-bg};
--#{$prefix}list-group-border-color: #{$list-group-border-color};
--#{$prefix}list-group-border-width: #{$list-group-border-width};
--#{$prefix}list-group-border-radius: #{$list-group-border-radius};
--#{$prefix}list-group-item-padding-x: #{$list-group-item-padding-x};
--#{$prefix}list-group-item-padding-y: #{$list-group-item-padding-y};
--#{$prefix}list-group-action-color: #{$list-group-action-color};
--#{$prefix}list-group-action-hover-color: #{$list-group-action-hover-color};
--#{$prefix}list-group-action-hover-bg: #{$list-group-hover-bg};
--#{$prefix}list-group-action-active-color: #{$list-group-action-active-color};
--#{$prefix}list-group-action-active-bg: #{$list-group-action-active-bg};
--#{$prefix}list-group-disabled-color: #{$list-group-disabled-color};
--#{$prefix}list-group-disabled-bg: #{$list-group-disabled-bg};
--#{$prefix}list-group-active-color: #{$list-group-active-color};
--#{$prefix}list-group-active-bg: #{$list-group-active-bg};
--#{$prefix}list-group-active-border-color: #{$list-group-active-border-color};
// scss-docs-end list-group-css-vars
display: flex;
flex-direction: column;
// No need to set list-style: none; since .list-group-item is block level
padding-left: 0; // reset padding because ul and ol
margin-bottom: 0;
@include border-radius($list-group-border-radius);
@include border-radius(var(--#{$prefix}list-group-border-radius));
}
.list-group-numbered {
list-style-type: none;
counter-reset: section;
> li::before {
> .list-group-item::before {
// Increments only this instance of the section counter
content: counters(section, ".") ". ";
counter-increment: section;
}
}
// Interactive list items
//
// Use anchor or button elements instead of `li`s or `div`s to create interactive
@ -31,25 +50,24 @@
.list-group-item-action {
width: 100%; // For `<button>`s (anchors become 100% by default though)
color: $list-group-action-color;
color: var(--#{$prefix}list-group-action-color);
text-align: inherit; // For `<button>`s (anchors inherit)
// Hover state
&:hover,
&:focus {
z-index: 1; // Place hover/focus items above their siblings for proper border styling
color: $list-group-action-hover-color;
color: var(--#{$prefix}list-group-action-hover-color);
text-decoration: none;
background-color: $list-group-hover-bg;
background-color: var(--#{$prefix}list-group-action-hover-bg);
}
&:active {
color: $list-group-action-active-color;
background-color: $list-group-action-active-bg;
color: var(--#{$prefix}list-group-action-active-color);
background-color: var(--#{$prefix}list-group-action-active-bg);
}
}
// Individual list items
//
// Use on `li`s or `div`s within the `.list-group` parent.
@ -57,11 +75,11 @@
.list-group-item {
position: relative;
display: block;
padding: $list-group-item-padding-y $list-group-item-padding-x;
color: $list-group-color;
padding: var(--#{$prefix}list-group-item-padding-y) var(--#{$prefix}list-group-item-padding-x);
color: var(--#{$prefix}list-group-color);
text-decoration: if($link-decoration == none, null, none);
background-color: $list-group-bg;
border: $list-group-border-width solid $list-group-border-color;
background-color: var(--#{$prefix}list-group-bg);
border: var(--#{$prefix}list-group-border-width) solid var(--#{$prefix}list-group-border-color);
&:first-child {
@include border-top-radius(inherit);
@ -73,30 +91,30 @@
&.disabled,
&:disabled {
color: $list-group-disabled-color;
color: var(--#{$prefix}list-group-disabled-color);
pointer-events: none;
background-color: $list-group-disabled-bg;
background-color: var(--#{$prefix}list-group-disabled-bg);
}
// Include both here for `<a>`s and `<button>`s
&.active {
z-index: 2; // Place active items above their siblings for proper border styling
color: $list-group-active-color;
background-color: $list-group-active-bg;
border-color: $list-group-active-border-color;
color: var(--#{$prefix}list-group-active-color);
background-color: var(--#{$prefix}list-group-active-bg);
border-color: var(--#{$prefix}list-group-active-border-color);
}
& + & {
// stylelint-disable-next-line scss/selector-no-redundant-nesting-selector
& + .list-group-item {
border-top-width: 0;
&.active {
margin-top: -$list-group-border-width;
border-top-width: $list-group-border-width;
margin-top: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list
border-top-width: var(--#{$prefix}list-group-border-width);
}
}
}
// Horizontal
//
// Change the layout of list group items from vertical (default) to horizontal.
@ -109,13 +127,13 @@
flex-direction: row;
> .list-group-item {
&:first-child {
@include border-bottom-start-radius($list-group-border-radius);
&:first-child:not(:last-child) {
@include border-bottom-start-radius(var(--#{$prefix}list-group-border-radius));
@include border-top-end-radius(0);
}
&:last-child {
@include border-top-end-radius($list-group-border-radius);
&:last-child:not(:first-child) {
@include border-top-end-radius(var(--#{$prefix}list-group-border-radius));
@include border-bottom-start-radius(0);
}
@ -124,12 +142,12 @@
}
+ .list-group-item {
border-top-width: $list-group-border-width;
border-top-width: var(--#{$prefix}list-group-border-width);
border-left-width: 0;
&.active {
margin-left: -$list-group-border-width;
border-left-width: $list-group-border-width;
margin-left: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list
border-left-width: var(--#{$prefix}list-group-border-width);
}
}
}
@ -147,7 +165,7 @@
@include border-radius(0);
> .list-group-item {
border-width: 0 0 $list-group-border-width;
border-width: 0 0 var(--#{$prefix}list-group-border-width);
&:last-child {
border-bottom-width: 0;
@ -162,13 +180,18 @@
// Add modifier classes to change text and background color on individual items.
// Organizationally, this must come after the `:hover` states.
@each $state, $value in $theme-colors {
$list-group-variant-bg: shift-color($value, $list-group-item-bg-scale);
$list-group-variant-color: shift-color($value, $list-group-item-color-scale);
@if (contrast-ratio($list-group-variant-bg, $list-group-variant-color) < $min-contrast-ratio) {
$list-group-variant-color: mix($value, color-contrast($list-group-variant-bg), abs($list-group-item-color-scale));
@each $state in map-keys($theme-colors) {
.list-group-item-#{$state} {
--#{$prefix}list-group-color: var(--#{$prefix}#{$state}-text-emphasis);
--#{$prefix}list-group-bg: var(--#{$prefix}#{$state}-bg-subtle);
--#{$prefix}list-group-border-color: var(--#{$prefix}#{$state}-border-subtle);
--#{$prefix}list-group-action-hover-color: var(--#{$prefix}emphasis-color);
--#{$prefix}list-group-action-hover-bg: var(--#{$prefix}#{$state}-border-subtle);
--#{$prefix}list-group-action-active-color: var(--#{$prefix}emphasis-color);
--#{$prefix}list-group-action-active-bg: var(--#{$prefix}#{$state}-border-subtle);
--#{$prefix}list-group-active-color: var(--#{$prefix}#{$state}-bg-subtle);
--#{$prefix}list-group-active-bg: var(--#{$prefix}#{$state}-text-emphasis);
--#{$prefix}list-group-active-border-color: var(--#{$prefix}#{$state}-text-emphasis);
}
@include list-group-item-variant($state, $list-group-variant-bg, $list-group-variant-color);
}
// scss-docs-end list-group-modifiers

View file

@ -0,0 +1,174 @@
// Re-assigned maps
//
// Placed here so that others can override the default Sass maps and see automatic updates to utilities and more.
// scss-docs-start theme-colors-rgb
$theme-colors-rgb: map-loop($theme-colors, to-rgb, "$value") !default;
// scss-docs-end theme-colors-rgb
// scss-docs-start theme-text-map
$theme-colors-text: (
"primary": $primary-text-emphasis,
"secondary": $secondary-text-emphasis,
"success": $success-text-emphasis,
"info": $info-text-emphasis,
"warning": $warning-text-emphasis,
"danger": $danger-text-emphasis,
"light": $light-text-emphasis,
"dark": $dark-text-emphasis,
) !default;
// scss-docs-end theme-text-map
// scss-docs-start theme-bg-subtle-map
$theme-colors-bg-subtle: (
"primary": $primary-bg-subtle,
"secondary": $secondary-bg-subtle,
"success": $success-bg-subtle,
"info": $info-bg-subtle,
"warning": $warning-bg-subtle,
"danger": $danger-bg-subtle,
"light": $light-bg-subtle,
"dark": $dark-bg-subtle,
) !default;
// scss-docs-end theme-bg-subtle-map
// scss-docs-start theme-border-subtle-map
$theme-colors-border-subtle: (
"primary": $primary-border-subtle,
"secondary": $secondary-border-subtle,
"success": $success-border-subtle,
"info": $info-border-subtle,
"warning": $warning-border-subtle,
"danger": $danger-border-subtle,
"light": $light-border-subtle,
"dark": $dark-border-subtle,
) !default;
// scss-docs-end theme-border-subtle-map
$theme-colors-text-dark: null !default;
$theme-colors-bg-subtle-dark: null !default;
$theme-colors-border-subtle-dark: null !default;
@if $enable-dark-mode {
// scss-docs-start theme-text-dark-map
$theme-colors-text-dark: (
"primary": $primary-text-emphasis-dark,
"secondary": $secondary-text-emphasis-dark,
"success": $success-text-emphasis-dark,
"info": $info-text-emphasis-dark,
"warning": $warning-text-emphasis-dark,
"danger": $danger-text-emphasis-dark,
"light": $light-text-emphasis-dark,
"dark": $dark-text-emphasis-dark,
) !default;
// scss-docs-end theme-text-dark-map
// scss-docs-start theme-bg-subtle-dark-map
$theme-colors-bg-subtle-dark: (
"primary": $primary-bg-subtle-dark,
"secondary": $secondary-bg-subtle-dark,
"success": $success-bg-subtle-dark,
"info": $info-bg-subtle-dark,
"warning": $warning-bg-subtle-dark,
"danger": $danger-bg-subtle-dark,
"light": $light-bg-subtle-dark,
"dark": $dark-bg-subtle-dark,
) !default;
// scss-docs-end theme-bg-subtle-dark-map
// scss-docs-start theme-border-subtle-dark-map
$theme-colors-border-subtle-dark: (
"primary": $primary-border-subtle-dark,
"secondary": $secondary-border-subtle-dark,
"success": $success-border-subtle-dark,
"info": $info-border-subtle-dark,
"warning": $warning-border-subtle-dark,
"danger": $danger-border-subtle-dark,
"light": $light-border-subtle-dark,
"dark": $dark-border-subtle-dark,
) !default;
// scss-docs-end theme-border-subtle-dark-map
}
// Utilities maps
//
// Extends the default `$theme-colors` maps to help create our utilities.
// Come v6, we'll de-dupe these variables. Until then, for backward compatibility, we keep them to reassign.
// scss-docs-start utilities-colors
$utilities-colors: $theme-colors-rgb !default;
// scss-docs-end utilities-colors
// scss-docs-start utilities-text-colors
$utilities-text: map-merge(
$utilities-colors,
(
"black": to-rgb($black),
"white": to-rgb($white),
"body": to-rgb($body-color)
)
) !default;
$utilities-text-colors: map-loop($utilities-text, rgba-css-var, "$key", "text") !default;
$utilities-text-emphasis-colors: (
"primary-emphasis": var(--#{$prefix}primary-text-emphasis),
"secondary-emphasis": var(--#{$prefix}secondary-text-emphasis),
"success-emphasis": var(--#{$prefix}success-text-emphasis),
"info-emphasis": var(--#{$prefix}info-text-emphasis),
"warning-emphasis": var(--#{$prefix}warning-text-emphasis),
"danger-emphasis": var(--#{$prefix}danger-text-emphasis),
"light-emphasis": var(--#{$prefix}light-text-emphasis),
"dark-emphasis": var(--#{$prefix}dark-text-emphasis)
) !default;
// scss-docs-end utilities-text-colors
// scss-docs-start utilities-bg-colors
$utilities-bg: map-merge(
$utilities-colors,
(
"black": to-rgb($black),
"white": to-rgb($white),
"body": to-rgb($body-bg)
)
) !default;
$utilities-bg-colors: map-loop($utilities-bg, rgba-css-var, "$key", "bg") !default;
$utilities-bg-subtle: (
"primary-subtle": var(--#{$prefix}primary-bg-subtle),
"secondary-subtle": var(--#{$prefix}secondary-bg-subtle),
"success-subtle": var(--#{$prefix}success-bg-subtle),
"info-subtle": var(--#{$prefix}info-bg-subtle),
"warning-subtle": var(--#{$prefix}warning-bg-subtle),
"danger-subtle": var(--#{$prefix}danger-bg-subtle),
"light-subtle": var(--#{$prefix}light-bg-subtle),
"dark-subtle": var(--#{$prefix}dark-bg-subtle)
) !default;
// scss-docs-end utilities-bg-colors
// scss-docs-start utilities-border-colors
$utilities-border: map-merge(
$utilities-colors,
(
"black": to-rgb($black),
"white": to-rgb($white)
)
) !default;
$utilities-border-colors: map-loop($utilities-border, rgba-css-var, "$key", "border") !default;
$utilities-border-subtle: (
"primary-subtle": var(--#{$prefix}primary-border-subtle),
"secondary-subtle": var(--#{$prefix}secondary-border-subtle),
"success-subtle": var(--#{$prefix}success-border-subtle),
"info-subtle": var(--#{$prefix}info-border-subtle),
"warning-subtle": var(--#{$prefix}warning-border-subtle),
"danger-subtle": var(--#{$prefix}danger-border-subtle),
"light-subtle": var(--#{$prefix}light-border-subtle),
"dark-subtle": var(--#{$prefix}dark-border-subtle)
) !default;
// scss-docs-end utilities-border-colors
$utilities-links-underline: map-loop($utilities-colors, rgba-css-var, "$key", "link-underline") !default;
$negative-spacers: if($enable-negative-margins, negativify-map($spacers), null) !default;
$gutters: $spacers !default;

View file

@ -10,6 +10,7 @@
// Helpers
@import "mixins/breakpoints";
@import "mixins/color-mode";
@import "mixins/color-scheme";
@import "mixins/image";
@import "mixins/resize";
@ -21,13 +22,11 @@
@import "mixins/utilities";
// Components
@import "mixins/alert";
@import "mixins/backdrop";
@import "mixins/buttons";
@import "mixins/caret";
@import "mixins/pagination";
@import "mixins/lists";
@import "mixins/list-group";
@import "mixins/forms";
@import "mixins/table-variants";

View file

@ -1,3 +1,5 @@
// stylelint-disable function-disallowed-list
// .modal-open - body class for killing the scroll
// .modal - container to scroll within
// .modal-dialog - positioning shell for the actual modal
@ -6,10 +8,34 @@
// Container that the modal scrolls within
.modal {
// scss-docs-start modal-css-vars
--#{$prefix}modal-zindex: #{$zindex-modal};
--#{$prefix}modal-width: #{$modal-md};
--#{$prefix}modal-padding: #{$modal-inner-padding};
--#{$prefix}modal-margin: #{$modal-dialog-margin};
--#{$prefix}modal-color: #{$modal-content-color};
--#{$prefix}modal-bg: #{$modal-content-bg};
--#{$prefix}modal-border-color: #{$modal-content-border-color};
--#{$prefix}modal-border-width: #{$modal-content-border-width};
--#{$prefix}modal-border-radius: #{$modal-content-border-radius};
--#{$prefix}modal-box-shadow: #{$modal-content-box-shadow-xs};
--#{$prefix}modal-inner-border-radius: #{$modal-content-inner-border-radius};
--#{$prefix}modal-header-padding-x: #{$modal-header-padding-x};
--#{$prefix}modal-header-padding-y: #{$modal-header-padding-y};
--#{$prefix}modal-header-padding: #{$modal-header-padding}; // Todo in v6: Split this padding into x and y
--#{$prefix}modal-header-border-color: #{$modal-header-border-color};
--#{$prefix}modal-header-border-width: #{$modal-header-border-width};
--#{$prefix}modal-title-line-height: #{$modal-title-line-height};
--#{$prefix}modal-footer-gap: #{$modal-footer-margin-between};
--#{$prefix}modal-footer-bg: #{$modal-footer-bg};
--#{$prefix}modal-footer-border-color: #{$modal-footer-border-color};
--#{$prefix}modal-footer-border-width: #{$modal-footer-border-width};
// scss-docs-end modal-css-vars
position: fixed;
top: 0;
left: 0;
z-index: $zindex-modal;
z-index: var(--#{$prefix}modal-zindex);
display: none;
width: 100%;
height: 100%;
@ -27,7 +53,7 @@
.modal-dialog {
position: relative;
width: auto;
margin: $modal-dialog-margin;
margin: var(--#{$prefix}modal-margin);
// allow clicks to pass through for custom click handling to close modal
pointer-events: none;
@ -47,7 +73,7 @@
}
.modal-dialog-scrollable {
height: subtract(100%, $modal-dialog-margin * 2);
height: calc(100% - var(--#{$prefix}modal-margin) * 2);
.modal-content {
max-height: 100%;
@ -62,7 +88,7 @@
.modal-dialog-centered {
display: flex;
align-items: center;
min-height: subtract(100%, $modal-dialog-margin * 2);
min-height: calc(100% - var(--#{$prefix}modal-margin) * 2);
}
// Actual modal
@ -72,20 +98,26 @@
flex-direction: column;
width: 100%; // Ensure `.modal-content` extends the full width of the parent `.modal-dialog`
// counteract the pointer-events: none; in the .modal-dialog
color: $modal-content-color;
color: var(--#{$prefix}modal-color);
pointer-events: auto;
background-color: $modal-content-bg;
background-color: var(--#{$prefix}modal-bg);
background-clip: padding-box;
border: $modal-content-border-width solid $modal-content-border-color;
@include border-radius($modal-content-border-radius);
@include box-shadow($modal-content-box-shadow-xs);
border: var(--#{$prefix}modal-border-width) solid var(--#{$prefix}modal-border-color);
@include border-radius(var(--#{$prefix}modal-border-radius));
@include box-shadow(var(--#{$prefix}modal-box-shadow));
// Remove focus outline from opened modal
outline: 0;
}
// Modal background
.modal-backdrop {
@include overlay-backdrop($zindex-modal-backdrop, $modal-backdrop-bg, $modal-backdrop-opacity);
// scss-docs-start modal-backdrop-css-vars
--#{$prefix}backdrop-zindex: #{$zindex-modal-backdrop};
--#{$prefix}backdrop-bg: #{$modal-backdrop-bg};
--#{$prefix}backdrop-opacity: #{$modal-backdrop-opacity};
// scss-docs-end modal-backdrop-css-vars
@include overlay-backdrop(var(--#{$prefix}backdrop-zindex), var(--#{$prefix}backdrop-bg), var(--#{$prefix}backdrop-opacity));
}
// Modal header
@ -94,21 +126,20 @@
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: space-between; // Put modal header elements (title and dismiss) on opposite ends
padding: $modal-header-padding;
border-bottom: $modal-header-border-width solid $modal-header-border-color;
@include border-top-radius($modal-content-inner-border-radius);
padding: var(--#{$prefix}modal-header-padding);
border-bottom: var(--#{$prefix}modal-header-border-width) solid var(--#{$prefix}modal-header-border-color);
@include border-top-radius(var(--#{$prefix}modal-inner-border-radius));
.btn-close {
padding: ($modal-header-padding-y * .5) ($modal-header-padding-x * .5);
margin: ($modal-header-padding-y * -.5) ($modal-header-padding-x * -.5) ($modal-header-padding-y * -.5) auto;
padding: calc(var(--#{$prefix}modal-header-padding-y) * .5) calc(var(--#{$prefix}modal-header-padding-x) * .5);
margin: calc(-.5 * var(--#{$prefix}modal-header-padding-y)) calc(-.5 * var(--#{$prefix}modal-header-padding-x)) calc(-.5 * var(--#{$prefix}modal-header-padding-y)) auto;
}
}
// Title text within header
.modal-title {
margin-bottom: 0;
line-height: $modal-title-line-height;
line-height: var(--#{$prefix}modal-title-line-height);
}
// Modal body
@ -118,60 +149,59 @@
// Enable `flex-grow: 1` so that the body take up as much space as possible
// when there should be a fixed height on `.modal-dialog`.
flex: 1 1 auto;
padding: $modal-inner-padding;
padding: var(--#{$prefix}modal-padding);
}
// Footer (for actions)
.modal-footer {
display: flex;
flex-wrap: wrap;
flex-shrink: 0;
flex-wrap: wrap;
align-items: center; // vertically center
justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items
padding: $modal-inner-padding - $modal-footer-margin-between * .5;
border-top: $modal-footer-border-width solid $modal-footer-border-color;
@include border-bottom-radius($modal-content-inner-border-radius);
padding: calc(var(--#{$prefix}modal-padding) - var(--#{$prefix}modal-footer-gap) * .5);
background-color: var(--#{$prefix}modal-footer-bg);
border-top: var(--#{$prefix}modal-footer-border-width) solid var(--#{$prefix}modal-footer-border-color);
@include border-bottom-radius(var(--#{$prefix}modal-inner-border-radius));
// Place margin between footer elements
// This solution is far from ideal because of the universal selector usage,
// but is needed to fix https://github.com/twbs/bootstrap/issues/24800
> * {
margin: $modal-footer-margin-between * .5;
margin: calc(var(--#{$prefix}modal-footer-gap) * .5); // Todo in v6: replace with gap on parent class
}
}
// Scale up the modal
@include media-breakpoint-up(sm) {
.modal {
--#{$prefix}modal-margin: #{$modal-dialog-margin-y-sm-up};
--#{$prefix}modal-box-shadow: #{$modal-content-box-shadow-sm-up};
}
// Automatically set modal's width for larger viewports
.modal-dialog {
max-width: $modal-md;
margin: $modal-dialog-margin-y-sm-up auto;
max-width: var(--#{$prefix}modal-width);
margin-right: auto;
margin-left: auto;
}
.modal-dialog-scrollable {
height: subtract(100%, $modal-dialog-margin-y-sm-up * 2);
.modal-sm {
--#{$prefix}modal-width: #{$modal-sm};
}
.modal-dialog-centered {
min-height: subtract(100%, $modal-dialog-margin-y-sm-up * 2);
}
.modal-content {
@include box-shadow($modal-content-box-shadow-sm-up);
}
.modal-sm { max-width: $modal-sm; }
}
@include media-breakpoint-up(lg) {
.modal-lg,
.modal-xl {
max-width: $modal-lg;
--#{$prefix}modal-width: #{$modal-lg};
}
}
@include media-breakpoint-up(xl) {
.modal-xl { max-width: $modal-xl; }
.modal-xl {
--#{$prefix}modal-width: #{$modal-xl};
}
}
// scss-docs-start modal-fullscreen-loop
@ -192,17 +222,14 @@
@include border-radius(0);
}
.modal-header {
.modal-header,
.modal-footer {
@include border-radius(0);
}
.modal-body {
overflow-y: auto;
}
.modal-footer {
@include border-radius(0);
}
}
}
}

View file

@ -4,6 +4,16 @@
// `<nav>`s, `<ul>`s or `<ol>`s.
.nav {
// scss-docs-start nav-css-vars
--#{$prefix}nav-link-padding-x: #{$nav-link-padding-x};
--#{$prefix}nav-link-padding-y: #{$nav-link-padding-y};
@include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size);
--#{$prefix}nav-link-font-weight: #{$nav-link-font-weight};
--#{$prefix}nav-link-color: #{$nav-link-color};
--#{$prefix}nav-link-hover-color: #{$nav-link-hover-color};
--#{$prefix}nav-link-disabled-color: #{$nav-link-disabled-color};
// scss-docs-end nav-css-vars
display: flex;
flex-wrap: wrap;
padding-left: 0;
@ -13,22 +23,30 @@
.nav-link {
display: block;
padding: $nav-link-padding-y $nav-link-padding-x;
@include font-size($nav-link-font-size);
font-weight: $nav-link-font-weight;
color: $nav-link-color;
padding: var(--#{$prefix}nav-link-padding-y) var(--#{$prefix}nav-link-padding-x);
@include font-size(var(--#{$prefix}nav-link-font-size));
font-weight: var(--#{$prefix}nav-link-font-weight);
color: var(--#{$prefix}nav-link-color);
text-decoration: if($link-decoration == none, null, none);
background: none;
border: 0;
@include transition($nav-link-transition);
&:hover,
&:focus {
color: $nav-link-hover-color;
color: var(--#{$prefix}nav-link-hover-color);
text-decoration: if($link-hover-decoration == underline, none, null);
}
&:focus-visible {
outline: 0;
box-shadow: $nav-link-focus-box-shadow;
}
// Disabled state lightens text
&.disabled {
color: $nav-link-disabled-color;
&.disabled,
&:disabled {
color: var(--#{$prefix}nav-link-disabled-color);
pointer-events: none;
cursor: default;
}
@ -39,38 +57,41 @@
//
.nav-tabs {
border-bottom: $nav-tabs-border-width solid $nav-tabs-border-color;
// scss-docs-start nav-tabs-css-vars
--#{$prefix}nav-tabs-border-width: #{$nav-tabs-border-width};
--#{$prefix}nav-tabs-border-color: #{$nav-tabs-border-color};
--#{$prefix}nav-tabs-border-radius: #{$nav-tabs-border-radius};
--#{$prefix}nav-tabs-link-hover-border-color: #{$nav-tabs-link-hover-border-color};
--#{$prefix}nav-tabs-link-active-color: #{$nav-tabs-link-active-color};
--#{$prefix}nav-tabs-link-active-bg: #{$nav-tabs-link-active-bg};
--#{$prefix}nav-tabs-link-active-border-color: #{$nav-tabs-link-active-border-color};
// scss-docs-end nav-tabs-css-vars
border-bottom: var(--#{$prefix}nav-tabs-border-width) solid var(--#{$prefix}nav-tabs-border-color);
.nav-link {
margin-bottom: -$nav-tabs-border-width;
background: none;
border: $nav-tabs-border-width solid transparent;
@include border-top-radius($nav-tabs-border-radius);
margin-bottom: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list
border: var(--#{$prefix}nav-tabs-border-width) solid transparent;
@include border-top-radius(var(--#{$prefix}nav-tabs-border-radius));
&:hover,
&:focus {
border-color: $nav-tabs-link-hover-border-color;
// Prevents active .nav-link tab overlapping focus outline of previous/next .nav-link
isolation: isolate;
}
&.disabled {
color: $nav-link-disabled-color;
background-color: transparent;
border-color: transparent;
border-color: var(--#{$prefix}nav-tabs-link-hover-border-color);
}
}
.nav-link.active,
.nav-item.show .nav-link {
color: $nav-tabs-link-active-color;
background-color: $nav-tabs-link-active-bg;
border-color: $nav-tabs-link-active-border-color;
color: var(--#{$prefix}nav-tabs-link-active-color);
background-color: var(--#{$prefix}nav-tabs-link-active-bg);
border-color: var(--#{$prefix}nav-tabs-link-active-border-color);
}
.dropdown-menu {
// Make dropdown border overlap tab border
margin-top: -$nav-tabs-border-width;
margin-top: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list
// Remove the top rounded corners here since there is a hard edge above the menu
@include border-top-radius(0);
}
@ -82,16 +103,53 @@
//
.nav-pills {
// scss-docs-start nav-pills-css-vars
--#{$prefix}nav-pills-border-radius: #{$nav-pills-border-radius};
--#{$prefix}nav-pills-link-active-color: #{$nav-pills-link-active-color};
--#{$prefix}nav-pills-link-active-bg: #{$nav-pills-link-active-bg};
// scss-docs-end nav-pills-css-vars
.nav-link {
background: none;
border: 0;
@include border-radius($nav-pills-border-radius);
@include border-radius(var(--#{$prefix}nav-pills-border-radius));
}
.nav-link.active,
.show > .nav-link {
color: $nav-pills-link-active-color;
@include gradient-bg($nav-pills-link-active-bg);
color: var(--#{$prefix}nav-pills-link-active-color);
@include gradient-bg(var(--#{$prefix}nav-pills-link-active-bg));
}
}
//
// Underline
//
.nav-underline {
// scss-docs-start nav-underline-css-vars
--#{$prefix}nav-underline-gap: #{$nav-underline-gap};
--#{$prefix}nav-underline-border-width: #{$nav-underline-border-width};
--#{$prefix}nav-underline-link-active-color: #{$nav-underline-link-active-color};
// scss-docs-end nav-underline-css-vars
gap: var(--#{$prefix}nav-underline-gap);
.nav-link {
padding-right: 0;
padding-left: 0;
border-bottom: var(--#{$prefix}nav-underline-border-width) solid transparent;
&:hover,
&:focus {
border-bottom-color: currentcolor;
}
}
.nav-link.active,
.show > .nav-link {
font-weight: $font-weight-bold;
color: var(--#{$prefix}nav-underline-link-active-color);
border-bottom-color: currentcolor;
}
}

View file

@ -1,29 +1,38 @@
// Contents
//
// Navbar
// Navbar brand
// Navbar nav
// Navbar text
// Responsive navbar
// Navbar position
// Navbar themes
// Navbar
//
// Provide a static navbar from which we expand to create full-width, fixed, and
// other navbar variations.
.navbar {
// scss-docs-start navbar-css-vars
--#{$prefix}navbar-padding-x: #{if($navbar-padding-x == null, 0, $navbar-padding-x)};
--#{$prefix}navbar-padding-y: #{$navbar-padding-y};
--#{$prefix}navbar-color: #{$navbar-light-color};
--#{$prefix}navbar-hover-color: #{$navbar-light-hover-color};
--#{$prefix}navbar-disabled-color: #{$navbar-light-disabled-color};
--#{$prefix}navbar-active-color: #{$navbar-light-active-color};
--#{$prefix}navbar-brand-padding-y: #{$navbar-brand-padding-y};
--#{$prefix}navbar-brand-margin-end: #{$navbar-brand-margin-end};
--#{$prefix}navbar-brand-font-size: #{$navbar-brand-font-size};
--#{$prefix}navbar-brand-color: #{$navbar-light-brand-color};
--#{$prefix}navbar-brand-hover-color: #{$navbar-light-brand-hover-color};
--#{$prefix}navbar-nav-link-padding-x: #{$navbar-nav-link-padding-x};
--#{$prefix}navbar-toggler-padding-y: #{$navbar-toggler-padding-y};
--#{$prefix}navbar-toggler-padding-x: #{$navbar-toggler-padding-x};
--#{$prefix}navbar-toggler-font-size: #{$navbar-toggler-font-size};
--#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-light-toggler-icon-bg)};
--#{$prefix}navbar-toggler-border-color: #{$navbar-light-toggler-border-color};
--#{$prefix}navbar-toggler-border-radius: #{$navbar-toggler-border-radius};
--#{$prefix}navbar-toggler-focus-width: #{$navbar-toggler-focus-width};
--#{$prefix}navbar-toggler-transition: #{$navbar-toggler-transition};
// scss-docs-end navbar-css-vars
position: relative;
display: flex;
flex-wrap: wrap; // allow us to do the line break for collapsing content
align-items: center;
justify-content: space-between; // space out brand from logo
padding-top: $navbar-padding-y;
padding-right: $navbar-padding-x; // default: null
padding-bottom: $navbar-padding-y;
padding-left: $navbar-padding-x; // default: null
padding: var(--#{$prefix}navbar-padding-y) var(--#{$prefix}navbar-padding-x);
@include gradient-bg();
// Because flex properties aren't inherited, we need to redeclare these first
@ -54,15 +63,17 @@
// Used for brand, project, or site names.
.navbar-brand {
padding-top: $navbar-brand-padding-y;
padding-bottom: $navbar-brand-padding-y;
margin-right: $navbar-brand-margin-end;
@include font-size($navbar-brand-font-size);
padding-top: var(--#{$prefix}navbar-brand-padding-y);
padding-bottom: var(--#{$prefix}navbar-brand-padding-y);
margin-right: var(--#{$prefix}navbar-brand-margin-end);
@include font-size(var(--#{$prefix}navbar-brand-font-size));
color: var(--#{$prefix}navbar-brand-color);
text-decoration: if($link-decoration == none, null, none);
white-space: nowrap;
&:hover,
&:focus {
color: var(--#{$prefix}navbar-brand-hover-color);
text-decoration: if($link-hover-decoration == underline, none, null);
}
}
@ -73,6 +84,16 @@
// Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`).
.navbar-nav {
// scss-docs-start navbar-nav-css-vars
--#{$prefix}nav-link-padding-x: 0;
--#{$prefix}nav-link-padding-y: #{$nav-link-padding-y};
@include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size);
--#{$prefix}nav-link-font-weight: #{$nav-link-font-weight};
--#{$prefix}nav-link-color: var(--#{$prefix}navbar-color);
--#{$prefix}nav-link-hover-color: var(--#{$prefix}navbar-hover-color);
--#{$prefix}nav-link-disabled-color: var(--#{$prefix}navbar-disabled-color);
// scss-docs-end navbar-nav-css-vars
display: flex;
flex-direction: column; // cannot use `inherit` to get the `.navbar`s value
padding-left: 0;
@ -80,8 +101,10 @@
list-style: none;
.nav-link {
padding-right: 0;
padding-left: 0;
&.active,
&.show {
color: var(--#{$prefix}navbar-active-color);
}
}
.dropdown-menu {
@ -97,6 +120,13 @@
.navbar-text {
padding-top: $nav-link-padding-y;
padding-bottom: $nav-link-padding-y;
color: var(--#{$prefix}navbar-color);
a,
a:hover,
a:focus {
color: var(--#{$prefix}navbar-active-color);
}
}
@ -118,13 +148,14 @@
// Button for toggling the navbar when in its collapsed state
.navbar-toggler {
padding: $navbar-toggler-padding-y $navbar-toggler-padding-x;
@include font-size($navbar-toggler-font-size);
padding: var(--#{$prefix}navbar-toggler-padding-y) var(--#{$prefix}navbar-toggler-padding-x);
@include font-size(var(--#{$prefix}navbar-toggler-font-size));
line-height: 1;
color: var(--#{$prefix}navbar-color);
background-color: transparent; // remove default button style
border: $border-width solid transparent; // remove default button style
@include border-radius($navbar-toggler-border-radius);
@include transition($navbar-toggler-transition);
border: var(--#{$prefix}border-width) solid var(--#{$prefix}navbar-toggler-border-color); // remove default button style
@include border-radius(var(--#{$prefix}navbar-toggler-border-radius));
@include transition(var(--#{$prefix}navbar-toggler-transition));
&:hover {
text-decoration: none;
@ -133,7 +164,7 @@
&:focus {
text-decoration: none;
outline: 0;
box-shadow: 0 0 0 $navbar-toggler-focus-width;
box-shadow: 0 0 0 var(--#{$prefix}navbar-toggler-focus-width);
}
}
@ -144,13 +175,14 @@
width: 1.5em;
height: 1.5em;
vertical-align: middle;
background-image: var(--#{$prefix}navbar-toggler-icon-bg);
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
}
.navbar-nav-scroll {
max-height: var(--#{$variable-prefix}scroll-height, 75vh);
max-height: var(--#{$prefix}scroll-height, 75vh);
overflow-y: auto;
}
@ -176,8 +208,8 @@
}
.nav-link {
padding-right: $navbar-nav-link-padding-x;
padding-left: $navbar-nav-link-padding-x;
padding-right: var(--#{$prefix}navbar-nav-link-padding-x);
padding-left: var(--#{$prefix}navbar-nav-link-padding-x);
}
}
@ -194,34 +226,31 @@
display: none;
}
.offcanvas-header {
display: none;
}
.offcanvas {
position: inherit;
bottom: 0;
z-index: 1000;
// stylelint-disable declaration-no-important
position: static;
z-index: auto;
flex-grow: 1;
visibility: visible !important; // stylelint-disable-line declaration-no-important
background-color: transparent;
border-right: 0;
border-left: 0;
width: auto !important;
height: auto !important;
visibility: visible !important;
background-color: transparent !important;
border: 0 !important;
transform: none !important;
@include box-shadow(none);
@include transition(none);
transform: none;
}
.offcanvas-top,
.offcanvas-bottom {
height: auto;
border-top: 0;
border-bottom: 0;
}
// stylelint-enable declaration-no-important
.offcanvas-body {
display: flex;
flex-grow: 0;
padding: 0;
overflow-y: visible;
.offcanvas-header {
display: none;
}
.offcanvas-body {
display: flex;
flex-grow: 0;
padding: 0;
overflow-y: visible;
}
}
}
}
@ -233,103 +262,28 @@
//
// Styles for switching between navbars with light or dark background.
// Dark links against a light background
.navbar-light {
.navbar-brand {
color: $navbar-light-brand-color;
@include deprecate("`.navbar-light`", "v5.2.0", "v6.0.0", true);
}
&:hover,
&:focus {
color: $navbar-light-brand-hover-color;
}
}
.navbar-dark,
.navbar[data-bs-theme="dark"] {
// scss-docs-start navbar-dark-css-vars
--#{$prefix}navbar-color: #{$navbar-dark-color};
--#{$prefix}navbar-hover-color: #{$navbar-dark-hover-color};
--#{$prefix}navbar-disabled-color: #{$navbar-dark-disabled-color};
--#{$prefix}navbar-active-color: #{$navbar-dark-active-color};
--#{$prefix}navbar-brand-color: #{$navbar-dark-brand-color};
--#{$prefix}navbar-brand-hover-color: #{$navbar-dark-brand-hover-color};
--#{$prefix}navbar-toggler-border-color: #{$navbar-dark-toggler-border-color};
--#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)};
// scss-docs-end navbar-dark-css-vars
}
.navbar-nav {
.nav-link {
color: $navbar-light-color;
&:hover,
&:focus {
color: $navbar-light-hover-color;
}
&.disabled {
color: $navbar-light-disabled-color;
}
}
.show > .nav-link,
.nav-link.active {
color: $navbar-light-active-color;
}
}
.navbar-toggler {
color: $navbar-light-color;
border-color: $navbar-light-toggler-border-color;
}
.navbar-toggler-icon {
background-image: escape-svg($navbar-light-toggler-icon-bg);
}
.navbar-text {
color: $navbar-light-color;
a,
a:hover,
a:focus {
color: $navbar-light-active-color;
}
}
}
// White links against a dark background
.navbar-dark {
.navbar-brand {
color: $navbar-dark-brand-color;
&:hover,
&:focus {
color: $navbar-dark-brand-hover-color;
}
}
.navbar-nav {
.nav-link {
color: $navbar-dark-color;
&:hover,
&:focus {
color: $navbar-dark-hover-color;
}
&.disabled {
color: $navbar-dark-disabled-color;
}
}
.show > .nav-link,
.nav-link.active {
color: $navbar-dark-active-color;
}
}
.navbar-toggler {
color: $navbar-dark-color;
border-color: $navbar-dark-toggler-border-color;
}
.navbar-toggler-icon {
background-image: escape-svg($navbar-dark-toggler-icon-bg);
}
.navbar-text {
color: $navbar-dark-color;
a,
a:hover,
a:focus {
color: $navbar-dark-active-color;
@if $enable-dark-mode {
@include color-mode(dark) {
.navbar-toggler-icon {
--#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)};
}
}
}

View file

@ -1,17 +1,119 @@
.offcanvas {
position: fixed;
bottom: 0;
z-index: $zindex-offcanvas;
display: flex;
flex-direction: column;
max-width: 100%;
color: $offcanvas-color;
visibility: hidden;
background-color: $offcanvas-bg-color;
background-clip: padding-box;
outline: 0;
@include box-shadow($offcanvas-box-shadow);
@include transition(transform $offcanvas-transition-duration ease-in-out);
// stylelint-disable function-disallowed-list
%offcanvas-css-vars {
// scss-docs-start offcanvas-css-vars
--#{$prefix}offcanvas-zindex: #{$zindex-offcanvas};
--#{$prefix}offcanvas-width: #{$offcanvas-horizontal-width};
--#{$prefix}offcanvas-height: #{$offcanvas-vertical-height};
--#{$prefix}offcanvas-padding-x: #{$offcanvas-padding-x};
--#{$prefix}offcanvas-padding-y: #{$offcanvas-padding-y};
--#{$prefix}offcanvas-color: #{$offcanvas-color};
--#{$prefix}offcanvas-bg: #{$offcanvas-bg-color};
--#{$prefix}offcanvas-border-width: #{$offcanvas-border-width};
--#{$prefix}offcanvas-border-color: #{$offcanvas-border-color};
--#{$prefix}offcanvas-box-shadow: #{$offcanvas-box-shadow};
--#{$prefix}offcanvas-transition: #{transform $offcanvas-transition-duration ease-in-out};
--#{$prefix}offcanvas-title-line-height: #{$offcanvas-title-line-height};
// scss-docs-end offcanvas-css-vars
}
@each $breakpoint in map-keys($grid-breakpoints) {
$next: breakpoint-next($breakpoint, $grid-breakpoints);
$infix: breakpoint-infix($next, $grid-breakpoints);
.offcanvas#{$infix} {
@extend %offcanvas-css-vars;
}
}
@each $breakpoint in map-keys($grid-breakpoints) {
$next: breakpoint-next($breakpoint, $grid-breakpoints);
$infix: breakpoint-infix($next, $grid-breakpoints);
.offcanvas#{$infix} {
@include media-breakpoint-down($next) {
position: fixed;
bottom: 0;
z-index: var(--#{$prefix}offcanvas-zindex);
display: flex;
flex-direction: column;
max-width: 100%;
color: var(--#{$prefix}offcanvas-color);
visibility: hidden;
background-color: var(--#{$prefix}offcanvas-bg);
background-clip: padding-box;
outline: 0;
@include box-shadow(var(--#{$prefix}offcanvas-box-shadow));
@include transition(var(--#{$prefix}offcanvas-transition));
&.offcanvas-start {
top: 0;
left: 0;
width: var(--#{$prefix}offcanvas-width);
border-right: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
transform: translateX(-100%);
}
&.offcanvas-end {
top: 0;
right: 0;
width: var(--#{$prefix}offcanvas-width);
border-left: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
transform: translateX(100%);
}
&.offcanvas-top {
top: 0;
right: 0;
left: 0;
height: var(--#{$prefix}offcanvas-height);
max-height: 100%;
border-bottom: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
transform: translateY(-100%);
}
&.offcanvas-bottom {
right: 0;
left: 0;
height: var(--#{$prefix}offcanvas-height);
max-height: 100%;
border-top: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
transform: translateY(100%);
}
&.showing,
&.show:not(.hiding) {
transform: none;
}
&.showing,
&.hiding,
&.show {
visibility: visible;
}
}
@if not ($infix == "") {
@include media-breakpoint-up($next) {
--#{$prefix}offcanvas-height: auto;
--#{$prefix}offcanvas-border-width: 0;
background-color: transparent !important; // stylelint-disable-line declaration-no-important
.offcanvas-header {
display: none;
}
.offcanvas-body {
display: flex;
flex-grow: 0;
padding: 0;
overflow-y: visible;
// Reset `background-color` in case `.bg-*` classes are used in offcanvas
background-color: transparent !important; // stylelint-disable-line declaration-no-important
}
}
}
}
}
.offcanvas-backdrop {
@ -21,63 +123,21 @@
.offcanvas-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: $offcanvas-padding-y $offcanvas-padding-x;
padding: var(--#{$prefix}offcanvas-padding-y) var(--#{$prefix}offcanvas-padding-x);
.btn-close {
padding: ($offcanvas-padding-y * .5) ($offcanvas-padding-x * .5);
margin-top: $offcanvas-padding-y * -.5;
margin-right: $offcanvas-padding-x * -.5;
margin-bottom: $offcanvas-padding-y * -.5;
padding: calc(var(--#{$prefix}offcanvas-padding-y) * .5) calc(var(--#{$prefix}offcanvas-padding-x) * .5);
margin: calc(-.5 * var(--#{$prefix}offcanvas-padding-y)) calc(-.5 * var(--#{$prefix}offcanvas-padding-x)) calc(-.5 * var(--#{$prefix}offcanvas-padding-y)) auto;
}
}
.offcanvas-title {
margin-bottom: 0;
line-height: $offcanvas-title-line-height;
line-height: var(--#{$prefix}offcanvas-title-line-height);
}
.offcanvas-body {
flex-grow: 1;
padding: $offcanvas-padding-y $offcanvas-padding-x;
padding: var(--#{$prefix}offcanvas-padding-y) var(--#{$prefix}offcanvas-padding-x);
overflow-y: auto;
}
.offcanvas-start {
top: 0;
left: 0;
width: $offcanvas-horizontal-width;
border-right: $offcanvas-border-width solid $offcanvas-border-color;
transform: translateX(-100%);
}
.offcanvas-end {
top: 0;
right: 0;
width: $offcanvas-horizontal-width;
border-left: $offcanvas-border-width solid $offcanvas-border-color;
transform: translateX(100%);
}
.offcanvas-top {
top: 0;
right: 0;
left: 0;
height: $offcanvas-vertical-height;
max-height: 100%;
border-bottom: $offcanvas-border-width solid $offcanvas-border-color;
transform: translateY(-100%);
}
.offcanvas-bottom {
right: 0;
left: 0;
height: $offcanvas-vertical-height;
max-height: 100%;
border-top: $offcanvas-border-width solid $offcanvas-border-color;
transform: translateY(100%);
}
.offcanvas.show {
transform: none;
}

View file

@ -1,4 +1,27 @@
.pagination {
// scss-docs-start pagination-css-vars
--#{$prefix}pagination-padding-x: #{$pagination-padding-x};
--#{$prefix}pagination-padding-y: #{$pagination-padding-y};
@include rfs($pagination-font-size, --#{$prefix}pagination-font-size);
--#{$prefix}pagination-color: #{$pagination-color};
--#{$prefix}pagination-bg: #{$pagination-bg};
--#{$prefix}pagination-border-width: #{$pagination-border-width};
--#{$prefix}pagination-border-color: #{$pagination-border-color};
--#{$prefix}pagination-border-radius: #{$pagination-border-radius};
--#{$prefix}pagination-hover-color: #{$pagination-hover-color};
--#{$prefix}pagination-hover-bg: #{$pagination-hover-bg};
--#{$prefix}pagination-hover-border-color: #{$pagination-hover-border-color};
--#{$prefix}pagination-focus-color: #{$pagination-focus-color};
--#{$prefix}pagination-focus-bg: #{$pagination-focus-bg};
--#{$prefix}pagination-focus-box-shadow: #{$pagination-focus-box-shadow};
--#{$prefix}pagination-active-color: #{$pagination-active-color};
--#{$prefix}pagination-active-bg: #{$pagination-active-bg};
--#{$prefix}pagination-active-border-color: #{$pagination-active-border-color};
--#{$prefix}pagination-disabled-color: #{$pagination-disabled-color};
--#{$prefix}pagination-disabled-bg: #{$pagination-disabled-bg};
--#{$prefix}pagination-disabled-border-color: #{$pagination-disabled-border-color};
// scss-docs-end pagination-css-vars
display: flex;
@include list-unstyled();
}
@ -6,26 +29,44 @@
.page-link {
position: relative;
display: block;
color: $pagination-color;
padding: var(--#{$prefix}pagination-padding-y) var(--#{$prefix}pagination-padding-x);
@include font-size(var(--#{$prefix}pagination-font-size));
color: var(--#{$prefix}pagination-color);
text-decoration: if($link-decoration == none, null, none);
background-color: $pagination-bg;
border: $pagination-border-width solid $pagination-border-color;
background-color: var(--#{$prefix}pagination-bg);
border: var(--#{$prefix}pagination-border-width) solid var(--#{$prefix}pagination-border-color);
@include transition($pagination-transition);
&:hover {
z-index: 2;
color: $pagination-hover-color;
color: var(--#{$prefix}pagination-hover-color);
text-decoration: if($link-hover-decoration == underline, none, null);
background-color: $pagination-hover-bg;
border-color: $pagination-hover-border-color;
background-color: var(--#{$prefix}pagination-hover-bg);
border-color: var(--#{$prefix}pagination-hover-border-color);
}
&:focus {
z-index: 3;
color: $pagination-focus-color;
background-color: $pagination-focus-bg;
color: var(--#{$prefix}pagination-focus-color);
background-color: var(--#{$prefix}pagination-focus-bg);
outline: $pagination-focus-outline;
box-shadow: $pagination-focus-box-shadow;
box-shadow: var(--#{$prefix}pagination-focus-box-shadow);
}
&.active,
.active > & {
z-index: 3;
color: var(--#{$prefix}pagination-active-color);
@include gradient-bg(var(--#{$prefix}pagination-active-bg));
border-color: var(--#{$prefix}pagination-active-border-color);
}
&.disabled,
.disabled > & {
color: var(--#{$prefix}pagination-disabled-color);
pointer-events: none;
background-color: var(--#{$prefix}pagination-disabled-bg);
border-color: var(--#{$prefix}pagination-disabled-border-color);
}
}
@ -34,18 +75,23 @@
margin-left: $pagination-margin-start;
}
&.active .page-link {
z-index: 3;
color: $pagination-active-color;
@include gradient-bg($pagination-active-bg);
border-color: $pagination-active-border-color;
}
@if $pagination-margin-start == calc(#{$pagination-border-width} * -1) {
&:first-child {
.page-link {
@include border-start-radius(var(--#{$prefix}pagination-border-radius));
}
}
&.disabled .page-link {
color: $pagination-disabled-color;
pointer-events: none;
background-color: $pagination-disabled-bg;
border-color: $pagination-disabled-border-color;
&:last-child {
.page-link {
@include border-end-radius(var(--#{$prefix}pagination-border-radius));
}
}
} @else {
// Add border-radius to all pageLinks in case they have left margin
.page-link {
@include border-radius(var(--#{$prefix}pagination-border-radius));
}
}
}
@ -53,7 +99,6 @@
//
// Sizing
//
@include pagination-size($pagination-padding-y, $pagination-padding-x, null, $pagination-border-radius);
.pagination-lg {
@include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $pagination-border-radius-lg);

View file

@ -3,7 +3,7 @@
min-height: 1em;
vertical-align: middle;
cursor: wait;
background-color: currentColor;
background-color: currentcolor;
opacity: $placeholder-opacity-max;
&.btn::before {

View file

@ -1,27 +1,46 @@
.popover {
position: absolute;
top: 0;
left: 0 #{"/* rtl:ignore */"};
z-index: $zindex-popover;
// scss-docs-start popover-css-vars
--#{$prefix}popover-zindex: #{$zindex-popover};
--#{$prefix}popover-max-width: #{$popover-max-width};
@include rfs($popover-font-size, --#{$prefix}popover-font-size);
--#{$prefix}popover-bg: #{$popover-bg};
--#{$prefix}popover-border-width: #{$popover-border-width};
--#{$prefix}popover-border-color: #{$popover-border-color};
--#{$prefix}popover-border-radius: #{$popover-border-radius};
--#{$prefix}popover-inner-border-radius: #{$popover-inner-border-radius};
--#{$prefix}popover-box-shadow: #{$popover-box-shadow};
--#{$prefix}popover-header-padding-x: #{$popover-header-padding-x};
--#{$prefix}popover-header-padding-y: #{$popover-header-padding-y};
@include rfs($popover-header-font-size, --#{$prefix}popover-header-font-size);
--#{$prefix}popover-header-color: #{$popover-header-color};
--#{$prefix}popover-header-bg: #{$popover-header-bg};
--#{$prefix}popover-body-padding-x: #{$popover-body-padding-x};
--#{$prefix}popover-body-padding-y: #{$popover-body-padding-y};
--#{$prefix}popover-body-color: #{$popover-body-color};
--#{$prefix}popover-arrow-width: #{$popover-arrow-width};
--#{$prefix}popover-arrow-height: #{$popover-arrow-height};
--#{$prefix}popover-arrow-border: var(--#{$prefix}popover-border-color);
// scss-docs-end popover-css-vars
z-index: var(--#{$prefix}popover-zindex);
display: block;
max-width: $popover-max-width;
max-width: var(--#{$prefix}popover-max-width);
// Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
// So reset our font and text properties to avoid inheriting weird values.
@include reset-text();
@include font-size($popover-font-size);
@include font-size(var(--#{$prefix}popover-font-size));
// Allow breaking very long words so they don't overflow the popover's bounds
word-wrap: break-word;
background-color: $popover-bg;
background-color: var(--#{$prefix}popover-bg);
background-clip: padding-box;
border: $popover-border-width solid $popover-border-color;
@include border-radius($popover-border-radius);
@include box-shadow($popover-box-shadow);
border: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color);
@include border-radius(var(--#{$prefix}popover-border-radius));
@include box-shadow(var(--#{$prefix}popover-box-shadow));
.popover-arrow {
position: absolute;
display: block;
width: $popover-arrow-width;
height: $popover-arrow-height;
width: var(--#{$prefix}popover-arrow-width);
height: var(--#{$prefix}popover-arrow-height);
&::before,
&::after {
@ -30,62 +49,75 @@
content: "";
border-color: transparent;
border-style: solid;
border-width: 0;
}
}
}
.bs-popover-top {
> .popover-arrow {
bottom: subtract(-$popover-arrow-height, $popover-border-width);
bottom: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
&::before,
&::after {
border-width: var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
}
&::before {
bottom: 0;
border-width: $popover-arrow-height ($popover-arrow-width * .5) 0;
border-top-color: $popover-arrow-outer-color;
border-top-color: var(--#{$prefix}popover-arrow-border);
}
&::after {
bottom: $popover-border-width;
border-width: $popover-arrow-height ($popover-arrow-width * .5) 0;
border-top-color: $popover-arrow-color;
bottom: var(--#{$prefix}popover-border-width);
border-top-color: var(--#{$prefix}popover-bg);
}
}
}
/* rtl:begin:ignore */
.bs-popover-end {
> .popover-arrow {
left: subtract(-$popover-arrow-height, $popover-border-width);
width: $popover-arrow-height;
height: $popover-arrow-width;
left: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
width: var(--#{$prefix}popover-arrow-height);
height: var(--#{$prefix}popover-arrow-width);
&::before,
&::after {
border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
}
&::before {
left: 0;
border-width: ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5) 0;
border-right-color: $popover-arrow-outer-color;
border-right-color: var(--#{$prefix}popover-arrow-border);
}
&::after {
left: $popover-border-width;
border-width: ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5) 0;
border-right-color: $popover-arrow-color;
left: var(--#{$prefix}popover-border-width);
border-right-color: var(--#{$prefix}popover-bg);
}
}
}
/* rtl:end:ignore */
.bs-popover-bottom {
> .popover-arrow {
top: subtract(-$popover-arrow-height, $popover-border-width);
top: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
&::before,
&::after {
border-width: 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list
}
&::before {
top: 0;
border-width: 0 ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5);
border-bottom-color: $popover-arrow-outer-color;
border-bottom-color: var(--#{$prefix}popover-arrow-border);
}
&::after {
top: $popover-border-width;
border-width: 0 ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5);
border-bottom-color: $popover-arrow-color;
top: var(--#{$prefix}popover-border-width);
border-bottom-color: var(--#{$prefix}popover-bg);
}
}
@ -95,33 +127,39 @@
top: 0;
left: 50%;
display: block;
width: $popover-arrow-width;
margin-left: -$popover-arrow-width * .5;
width: var(--#{$prefix}popover-arrow-width);
margin-left: calc(-.5 * var(--#{$prefix}popover-arrow-width)); // stylelint-disable-line function-disallowed-list
content: "";
border-bottom: $popover-border-width solid $popover-header-bg;
border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-header-bg);
}
}
/* rtl:begin:ignore */
.bs-popover-start {
> .popover-arrow {
right: subtract(-$popover-arrow-height, $popover-border-width);
width: $popover-arrow-height;
height: $popover-arrow-width;
right: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
width: var(--#{$prefix}popover-arrow-height);
height: var(--#{$prefix}popover-arrow-width);
&::before,
&::after {
border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list
}
&::before {
right: 0;
border-width: ($popover-arrow-width * .5) 0 ($popover-arrow-width * .5) $popover-arrow-height;
border-left-color: $popover-arrow-outer-color;
border-left-color: var(--#{$prefix}popover-arrow-border);
}
&::after {
right: $popover-border-width;
border-width: ($popover-arrow-width * .5) 0 ($popover-arrow-width * .5) $popover-arrow-height;
border-left-color: $popover-arrow-color;
right: var(--#{$prefix}popover-border-width);
border-left-color: var(--#{$prefix}popover-bg);
}
}
}
/* rtl:end:ignore */
.bs-popover-auto {
&[data-popper-placement^="top"] {
@extend .bs-popover-top;
@ -139,13 +177,13 @@
// Offset the popover to account for the popover arrow
.popover-header {
padding: $popover-header-padding-y $popover-header-padding-x;
padding: var(--#{$prefix}popover-header-padding-y) var(--#{$prefix}popover-header-padding-x);
margin-bottom: 0; // Reset the default from Reboot
@include font-size($font-size-base);
color: $popover-header-color;
background-color: $popover-header-bg;
border-bottom: $popover-border-width solid $popover-border-color;
@include border-top-radius($popover-inner-border-radius);
@include font-size(var(--#{$prefix}popover-header-font-size));
color: var(--#{$prefix}popover-header-color);
background-color: var(--#{$prefix}popover-header-bg);
border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color);
@include border-top-radius(var(--#{$prefix}popover-inner-border-radius));
&:empty {
display: none;
@ -153,6 +191,6 @@
}
.popover-body {
padding: $popover-body-padding-y $popover-body-padding-x;
color: $popover-body-color;
padding: var(--#{$prefix}popover-body-padding-y) var(--#{$prefix}popover-body-padding-x);
color: var(--#{$prefix}popover-body-color);
}

View file

@ -8,14 +8,26 @@
}
// scss-docs-end progress-keyframes
.progress {
.progress,
.progress-stacked {
// scss-docs-start progress-css-vars
--#{$prefix}progress-height: #{$progress-height};
@include rfs($progress-font-size, --#{$prefix}progress-font-size);
--#{$prefix}progress-bg: #{$progress-bg};
--#{$prefix}progress-border-radius: #{$progress-border-radius};
--#{$prefix}progress-box-shadow: #{$progress-box-shadow};
--#{$prefix}progress-bar-color: #{$progress-bar-color};
--#{$prefix}progress-bar-bg: #{$progress-bar-bg};
--#{$prefix}progress-bar-transition: #{$progress-bar-transition};
// scss-docs-end progress-css-vars
display: flex;
height: $progress-height;
height: var(--#{$prefix}progress-height);
overflow: hidden; // force rounded corners by cropping it
@include font-size($progress-font-size);
background-color: $progress-bg;
@include border-radius($progress-border-radius);
@include box-shadow($progress-box-shadow);
@include font-size(var(--#{$prefix}progress-font-size));
background-color: var(--#{$prefix}progress-bg);
@include border-radius(var(--#{$prefix}progress-border-radius));
@include box-shadow(var(--#{$prefix}progress-box-shadow));
}
.progress-bar {
@ -23,16 +35,24 @@
flex-direction: column;
justify-content: center;
overflow: hidden;
color: $progress-bar-color;
color: var(--#{$prefix}progress-bar-color);
text-align: center;
white-space: nowrap;
background-color: $progress-bar-bg;
@include transition($progress-bar-transition);
background-color: var(--#{$prefix}progress-bar-bg);
@include transition(var(--#{$prefix}progress-bar-transition));
}
.progress-bar-striped {
@include gradient-striped();
background-size: $progress-height $progress-height;
background-size: var(--#{$prefix}progress-height) var(--#{$prefix}progress-height);
}
.progress-stacked > .progress {
overflow: visible;
}
.progress-stacked > .progress > .progress-bar {
width: 100%;
}
@if $enable-transitions {

View file

@ -27,7 +27,7 @@
:root {
@if $font-size-root != null {
font-size: var(--#{$variable-prefix}root-font-size);
@include font-size(var(--#{$prefix}root-font-size));
}
@if $enable-smooth-scroll {
@ -48,13 +48,13 @@
// scss-docs-start reboot-body-rules
body {
margin: 0; // 1
font-family: var(--#{$variable-prefix}body-font-family);
@include font-size(var(--#{$variable-prefix}body-font-size));
font-weight: var(--#{$variable-prefix}body-font-weight);
line-height: var(--#{$variable-prefix}body-line-height);
color: var(--#{$variable-prefix}body-color);
text-align: var(--#{$variable-prefix}body-text-align);
background-color: var(--#{$variable-prefix}body-bg); // 2
font-family: var(--#{$prefix}body-font-family);
@include font-size(var(--#{$prefix}body-font-size));
font-weight: var(--#{$prefix}body-font-weight);
line-height: var(--#{$prefix}body-line-height);
color: var(--#{$prefix}body-color);
text-align: var(--#{$prefix}body-text-align);
background-color: var(--#{$prefix}body-bg); // 2
-webkit-text-size-adjust: 100%; // 3
-webkit-tap-highlight-color: rgba($black, 0); // 4
}
@ -64,20 +64,15 @@ body {
// Content grouping
//
// 1. Reset Firefox's gray color
// 2. Set correct height and prevent the `size` attribute to make the `hr` look like an input field
hr {
margin: $hr-margin-y 0;
color: $hr-color; // 1
background-color: currentColor;
border: 0;
border-top: $hr-border-width solid $hr-border-color;
opacity: $hr-opacity;
}
hr:not([size]) {
height: $hr-height; // 2
}
// Typography
//
@ -92,7 +87,7 @@ hr:not([size]) {
font-style: $headings-font-style;
font-weight: $headings-font-weight;
line-height: $headings-line-height;
color: $headings-color;
color: var(--#{$prefix}heading-color);
}
h1 {
@ -139,16 +134,14 @@ p {
// Abbreviations
//
// 1. Duplicate behavior to the data-bs-* attribute for our tooltip plugin
// 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.
// 3. Add explicit cursor to indicate changed behavior.
// 4. Prevent the text-decoration to be skipped.
// 1. Add the correct text decoration in Chrome, Edge, Opera, and Safari.
// 2. Add explicit cursor to indicate changed behavior.
// 3. Prevent the text-decoration to be skipped.
abbr[title],
abbr[data-bs-original-title] { // 1
text-decoration: underline dotted; // 2
cursor: help; // 3
text-decoration-skip-ink: none; // 4
abbr[title] {
text-decoration: underline dotted; // 1
cursor: help; // 2
text-decoration-skip-ink: none; // 3
}
@ -224,7 +217,8 @@ small {
mark {
padding: $mark-padding;
background-color: $mark-bg;
color: var(--#{$prefix}highlight-color);
background-color: var(--#{$prefix}highlight-bg);
}
@ -248,11 +242,11 @@ sup { top: -.5em; }
// Links
a {
color: $link-color;
color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, 1));
text-decoration: $link-decoration;
&:hover {
color: $link-hover-color;
--#{$prefix}link-color-rgb: var(--#{$prefix}link-hover-color-rgb);
text-decoration: $link-hover-decoration;
}
}
@ -279,8 +273,6 @@ kbd,
samp {
font-family: $font-family-code;
@include font-size(1em); // Correct the odd `em` font sizing in all browsers.
direction: ltr #{"/* rtl:ignore */"};
unicode-bidi: bidi-override;
}
// 1. Remove browser default top margin
@ -305,7 +297,7 @@ pre {
code {
@include font-size($code-font-size);
color: $code-color;
color: var(--#{$prefix}code-color);
word-wrap: break-word;
// Streamline the style when inside anchors to avoid broken underline and more
@ -445,11 +437,11 @@ select {
}
}
// Remove the dropdown arrow in Chrome from inputs built with datalists.
// Remove the dropdown arrow only from text type inputs built with datalists in Chrome.
// See https://stackoverflow.com/a/54997118
[list]::-webkit-calendar-picker-indicator {
display: none;
[list]:not([type="date"]):not([type="datetime-local"]):not([type="month"]):not([type="week"]):not([type="time"])::-webkit-calendar-picker-indicator {
display: none !important;
}
// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
@ -533,15 +525,15 @@ legend {
height: auto;
}
// 1. Correct the outline style in Safari.
// 2. This overrides the extra rounded corners on search inputs in iOS so that our
// 1. This overrides the extra rounded corners on search inputs in iOS so that our
// `.form-control` class can properly style them. Note that this cannot simply
// be added to `.form-control` as it's not specific enough. For details, see
// https://github.com/twbs/bootstrap/issues/11586.
// 2. Correct the outline style in Safari.
[type="search"] {
outline-offset: -2px; // 1
-webkit-appearance: textfield; // 2
-webkit-appearance: textfield; // 1
outline-offset: -2px; // 2
}
// 1. A few input types should stay LTR
@ -571,16 +563,10 @@ legend {
}
// Inherit font family and line height for file input buttons
::file-selector-button {
font: inherit;
}
// 1. Change font properties to `inherit`
// 1. Inherit font family and line height for file input buttons
// 2. Correct the inability to style clickable types in iOS and Safari.
::-webkit-file-upload-button {
::file-selector-button {
font: inherit; // 1
-webkit-appearance: button; // 2
}

View file

@ -1,4 +1,5 @@
:root {
:root,
[data-bs-theme="light"] {
// Note: Custom variable values only support SassScript inside `#{}`.
// Colors
@ -6,49 +7,181 @@
// Generate palettes for full colors, grays, and theme colors.
@each $color, $value in $colors {
--#{$variable-prefix}#{$color}: #{$value};
--#{$prefix}#{$color}: #{$value};
}
@each $color, $value in $grays {
--#{$variable-prefix}gray-#{$color}: #{$value};
--#{$prefix}gray-#{$color}: #{$value};
}
@each $color, $value in $theme-colors {
--#{$variable-prefix}#{$color}: #{$value};
--#{$prefix}#{$color}: #{$value};
}
@each $color, $value in $theme-colors-rgb {
--#{$variable-prefix}#{$color}-rgb: #{$value};
--#{$prefix}#{$color}-rgb: #{$value};
}
--#{$variable-prefix}white-rgb: #{to-rgb($white)};
--#{$variable-prefix}black-rgb: #{to-rgb($black)};
--#{$variable-prefix}body-color-rgb: #{to-rgb($body-color)};
--#{$variable-prefix}body-bg-rgb: #{to-rgb($body-bg)};
@each $color, $value in $theme-colors-text {
--#{$prefix}#{$color}-text-emphasis: #{$value};
}
@each $color, $value in $theme-colors-bg-subtle {
--#{$prefix}#{$color}-bg-subtle: #{$value};
}
@each $color, $value in $theme-colors-border-subtle {
--#{$prefix}#{$color}-border-subtle: #{$value};
}
--#{$prefix}white-rgb: #{to-rgb($white)};
--#{$prefix}black-rgb: #{to-rgb($black)};
// Fonts
// Note: Use `inspect` for lists so that quoted items keep the quotes.
// See https://github.com/sass/sass/issues/2383#issuecomment-336349172
--#{$variable-prefix}font-sans-serif: #{inspect($font-family-sans-serif)};
--#{$variable-prefix}font-monospace: #{inspect($font-family-monospace)};
--#{$variable-prefix}gradient: #{$gradient};
--#{$prefix}font-sans-serif: #{inspect($font-family-sans-serif)};
--#{$prefix}font-monospace: #{inspect($font-family-monospace)};
--#{$prefix}gradient: #{$gradient};
// Root and body
// stylelint-disable custom-property-empty-line-before
// scss-docs-start root-body-variables
@if $font-size-root != null {
--#{$variable-prefix}root-font-size: #{$font-size-root};
--#{$prefix}root-font-size: #{$font-size-root};
}
--#{$variable-prefix}body-font-family: #{$font-family-base};
--#{$variable-prefix}body-font-size: #{$font-size-base};
--#{$variable-prefix}body-font-weight: #{$font-weight-base};
--#{$variable-prefix}body-line-height: #{$line-height-base};
--#{$variable-prefix}body-color: #{$body-color};
--#{$prefix}body-font-family: #{inspect($font-family-base)};
@include rfs($font-size-base, --#{$prefix}body-font-size);
--#{$prefix}body-font-weight: #{$font-weight-base};
--#{$prefix}body-line-height: #{$line-height-base};
@if $body-text-align != null {
--#{$variable-prefix}body-text-align: #{$body-text-align};
--#{$prefix}body-text-align: #{$body-text-align};
}
--#{$variable-prefix}body-bg: #{$body-bg};
--#{$prefix}body-color: #{$body-color};
--#{$prefix}body-color-rgb: #{to-rgb($body-color)};
--#{$prefix}body-bg: #{$body-bg};
--#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};
--#{$prefix}emphasis-color: #{$body-emphasis-color};
--#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color)};
--#{$prefix}secondary-color: #{$body-secondary-color};
--#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color)};
--#{$prefix}secondary-bg: #{$body-secondary-bg};
--#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg)};
--#{$prefix}tertiary-color: #{$body-tertiary-color};
--#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color)};
--#{$prefix}tertiary-bg: #{$body-tertiary-bg};
--#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg)};
// scss-docs-end root-body-variables
// stylelint-enable custom-property-empty-line-before
--#{$prefix}heading-color: #{$headings-color};
--#{$prefix}link-color: #{$link-color};
--#{$prefix}link-color-rgb: #{to-rgb($link-color)};
--#{$prefix}link-decoration: #{$link-decoration};
--#{$prefix}link-hover-color: #{$link-hover-color};
--#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color)};
@if $link-hover-decoration != null {
--#{$prefix}link-hover-decoration: #{$link-hover-decoration};
}
--#{$prefix}code-color: #{$code-color};
--#{$prefix}highlight-color: #{$mark-color};
--#{$prefix}highlight-bg: #{$mark-bg};
// scss-docs-start root-border-var
--#{$prefix}border-width: #{$border-width};
--#{$prefix}border-style: #{$border-style};
--#{$prefix}border-color: #{$border-color};
--#{$prefix}border-color-translucent: #{$border-color-translucent};
--#{$prefix}border-radius: #{$border-radius};
--#{$prefix}border-radius-sm: #{$border-radius-sm};
--#{$prefix}border-radius-lg: #{$border-radius-lg};
--#{$prefix}border-radius-xl: #{$border-radius-xl};
--#{$prefix}border-radius-xxl: #{$border-radius-xxl};
--#{$prefix}border-radius-2xl: var(--#{$prefix}border-radius-xxl); // Deprecated in v5.3.0 for consistency
--#{$prefix}border-radius-pill: #{$border-radius-pill};
// scss-docs-end root-border-var
--#{$prefix}box-shadow: #{$box-shadow};
--#{$prefix}box-shadow-sm: #{$box-shadow-sm};
--#{$prefix}box-shadow-lg: #{$box-shadow-lg};
--#{$prefix}box-shadow-inset: #{$box-shadow-inset};
// Focus styles
// scss-docs-start root-focus-variables
--#{$prefix}focus-ring-width: #{$focus-ring-width};
--#{$prefix}focus-ring-opacity: #{$focus-ring-opacity};
--#{$prefix}focus-ring-color: #{$focus-ring-color};
// scss-docs-end root-focus-variables
// scss-docs-start root-form-validation-variables
--#{$prefix}form-valid-color: #{$form-valid-color};
--#{$prefix}form-valid-border-color: #{$form-valid-border-color};
--#{$prefix}form-invalid-color: #{$form-invalid-color};
--#{$prefix}form-invalid-border-color: #{$form-invalid-border-color};
// scss-docs-end root-form-validation-variables
}
@if $enable-dark-mode {
@include color-mode(dark, true) {
color-scheme: dark;
// scss-docs-start root-dark-mode-vars
--#{$prefix}body-color: #{$body-color-dark};
--#{$prefix}body-color-rgb: #{to-rgb($body-color-dark)};
--#{$prefix}body-bg: #{$body-bg-dark};
--#{$prefix}body-bg-rgb: #{to-rgb($body-bg-dark)};
--#{$prefix}emphasis-color: #{$body-emphasis-color-dark};
--#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color-dark)};
--#{$prefix}secondary-color: #{$body-secondary-color-dark};
--#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color-dark)};
--#{$prefix}secondary-bg: #{$body-secondary-bg-dark};
--#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg-dark)};
--#{$prefix}tertiary-color: #{$body-tertiary-color-dark};
--#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color-dark)};
--#{$prefix}tertiary-bg: #{$body-tertiary-bg-dark};
--#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg-dark)};
@each $color, $value in $theme-colors-text-dark {
--#{$prefix}#{$color}-text-emphasis: #{$value};
}
@each $color, $value in $theme-colors-bg-subtle-dark {
--#{$prefix}#{$color}-bg-subtle: #{$value};
}
@each $color, $value in $theme-colors-border-subtle-dark {
--#{$prefix}#{$color}-border-subtle: #{$value};
}
--#{$prefix}heading-color: #{$headings-color-dark};
--#{$prefix}link-color: #{$link-color-dark};
--#{$prefix}link-hover-color: #{$link-hover-color-dark};
--#{$prefix}link-color-rgb: #{to-rgb($link-color-dark)};
--#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color-dark)};
--#{$prefix}code-color: #{$code-color-dark};
--#{$prefix}highlight-color: #{$mark-color-dark};
--#{$prefix}highlight-bg: #{$mark-bg-dark};
--#{$prefix}border-color: #{$border-color-dark};
--#{$prefix}border-color-translucent: #{$border-color-translucent-dark};
--#{$prefix}form-valid-color: #{$form-valid-color-dark};
--#{$prefix}form-valid-border-color: #{$form-valid-border-color-dark};
--#{$prefix}form-invalid-color: #{$form-invalid-color-dark};
--#{$prefix}form-invalid-border-color: #{$form-invalid-border-color-dark};
// scss-docs-end root-dark-mode-vars
}
}

View file

@ -2,6 +2,17 @@
// Rotating border
//
.spinner-grow,
.spinner-border {
display: inline-block;
width: var(--#{$prefix}spinner-width);
height: var(--#{$prefix}spinner-height);
vertical-align: var(--#{$prefix}spinner-vertical-align);
// stylelint-disable-next-line property-disallowed-list
border-radius: 50%;
animation: var(--#{$prefix}spinner-animation-speed) linear infinite var(--#{$prefix}spinner-animation-name);
}
// scss-docs-start spinner-border-keyframes
@keyframes spinner-border {
to { transform: rotate(360deg) #{"/* rtl:ignore */"}; }
@ -9,21 +20,25 @@
// scss-docs-end spinner-border-keyframes
.spinner-border {
display: inline-block;
width: $spinner-width;
height: $spinner-height;
vertical-align: $spinner-vertical-align;
border: $spinner-border-width solid currentColor;
// scss-docs-start spinner-border-css-vars
--#{$prefix}spinner-width: #{$spinner-width};
--#{$prefix}spinner-height: #{$spinner-height};
--#{$prefix}spinner-vertical-align: #{$spinner-vertical-align};
--#{$prefix}spinner-border-width: #{$spinner-border-width};
--#{$prefix}spinner-animation-speed: #{$spinner-animation-speed};
--#{$prefix}spinner-animation-name: spinner-border;
// scss-docs-end spinner-border-css-vars
border: var(--#{$prefix}spinner-border-width) solid currentcolor;
border-right-color: transparent;
// stylelint-disable-next-line property-disallowed-list
border-radius: 50%;
animation: $spinner-animation-speed linear infinite spinner-border;
}
.spinner-border-sm {
width: $spinner-width-sm;
height: $spinner-height-sm;
border-width: $spinner-border-width-sm;
// scss-docs-start spinner-border-sm-css-vars
--#{$prefix}spinner-width: #{$spinner-width-sm};
--#{$prefix}spinner-height: #{$spinner-height-sm};
--#{$prefix}spinner-border-width: #{$spinner-border-width-sm};
// scss-docs-end spinner-border-sm-css-vars
}
//
@ -43,27 +58,28 @@
// scss-docs-end spinner-grow-keyframes
.spinner-grow {
display: inline-block;
width: $spinner-width;
height: $spinner-height;
vertical-align: $spinner-vertical-align;
background-color: currentColor;
// stylelint-disable-next-line property-disallowed-list
border-radius: 50%;
// scss-docs-start spinner-grow-css-vars
--#{$prefix}spinner-width: #{$spinner-width};
--#{$prefix}spinner-height: #{$spinner-height};
--#{$prefix}spinner-vertical-align: #{$spinner-vertical-align};
--#{$prefix}spinner-animation-speed: #{$spinner-animation-speed};
--#{$prefix}spinner-animation-name: spinner-grow;
// scss-docs-end spinner-grow-css-vars
background-color: currentcolor;
opacity: 0;
animation: $spinner-animation-speed linear infinite spinner-grow;
}
.spinner-grow-sm {
width: $spinner-width-sm;
height: $spinner-height-sm;
--#{$prefix}spinner-width: #{$spinner-width-sm};
--#{$prefix}spinner-height: #{$spinner-height-sm};
}
@if $enable-reduced-motion {
@media (prefers-reduced-motion: reduce) {
.spinner-border,
.spinner-grow {
animation-duration: $spinner-animation-speed * 2;
--#{$prefix}spinner-animation-speed: #{$spinner-animation-speed * 2};
}
}
}

View file

@ -3,20 +3,27 @@
//
.table {
--#{$variable-prefix}table-bg: #{$table-bg};
--#{$variable-prefix}table-accent-bg: #{$table-accent-bg};
--#{$variable-prefix}table-striped-color: #{$table-striped-color};
--#{$variable-prefix}table-striped-bg: #{$table-striped-bg};
--#{$variable-prefix}table-active-color: #{$table-active-color};
--#{$variable-prefix}table-active-bg: #{$table-active-bg};
--#{$variable-prefix}table-hover-color: #{$table-hover-color};
--#{$variable-prefix}table-hover-bg: #{$table-hover-bg};
// Reset needed for nesting tables
--#{$prefix}table-color-type: initial;
--#{$prefix}table-bg-type: initial;
--#{$prefix}table-color-state: initial;
--#{$prefix}table-bg-state: initial;
// End of reset
--#{$prefix}table-color: #{$table-color};
--#{$prefix}table-bg: #{$table-bg};
--#{$prefix}table-border-color: #{$table-border-color};
--#{$prefix}table-accent-bg: #{$table-accent-bg};
--#{$prefix}table-striped-color: #{$table-striped-color};
--#{$prefix}table-striped-bg: #{$table-striped-bg};
--#{$prefix}table-active-color: #{$table-active-color};
--#{$prefix}table-active-bg: #{$table-active-bg};
--#{$prefix}table-hover-color: #{$table-hover-color};
--#{$prefix}table-hover-bg: #{$table-hover-bg};
width: 100%;
margin-bottom: $spacer;
color: $table-color;
vertical-align: $table-cell-vertical-align;
border-color: $table-border-color;
border-color: var(--#{$prefix}table-border-color);
// Target th & td
// We need the child combinator to prevent styles leaking to nested tables which doesn't have a `.table` class.
@ -25,9 +32,11 @@
// stylelint-disable-next-line selector-max-universal
> :not(caption) > * > * {
padding: $table-cell-padding-y $table-cell-padding-x;
background-color: var(--#{$variable-prefix}table-bg);
// Following the precept of cascades: https://codepen.io/miriamsuzanne/full/vYNgodb
color: var(--#{$prefix}table-color-state, var(--#{$prefix}table-color-type, var(--#{$prefix}table-color)));
background-color: var(--#{$prefix}table-bg);
border-bottom-width: $table-border-width;
box-shadow: inset 0 0 0 9999px var(--#{$variable-prefix}table-accent-bg);
box-shadow: inset 0 0 0 9999px var(--#{$prefix}table-bg-state, var(--#{$prefix}table-bg-type, var(--#{$prefix}table-accent-bg)));
}
> tbody {
@ -37,13 +46,11 @@
> thead {
vertical-align: bottom;
}
// Highlight border color between thead, tbody and tfoot.
> :not(:first-child) {
border-top: (2 * $table-border-width) solid $table-group-separator-color;
}
}
.table-group-divider {
border-top: calc(#{$table-border-width} * 2) solid $table-group-separator-color; // stylelint-disable-line function-disallowed-list
}
//
// Change placement of captions with a class
@ -72,7 +79,7 @@
//
// When borders are added on all sides of the cells, the corners can render odd when
// these borders do not have the same color or if they are semi-transparent.
// Therefor we add top and border bottoms to the `tr`s and left and right borders
// Therefore we add top and border bottoms to the `tr`s and left and right borders
// to the `td`s or `th`s
.table-bordered {
@ -101,10 +108,19 @@
//
// Default zebra-stripe styles (alternating gray and transparent backgrounds)
// For rows
.table-striped {
> tbody > tr:nth-of-type(#{$table-striped-order}) > * {
--#{$variable-prefix}table-accent-bg: var(--#{$variable-prefix}table-striped-bg);
color: var(--#{$variable-prefix}table-striped-color);
--#{$prefix}table-color-type: var(--#{$prefix}table-striped-color);
--#{$prefix}table-bg-type: var(--#{$prefix}table-striped-bg);
}
}
// For columns
.table-striped-columns {
> :not(caption) > tr > :nth-child(#{$table-striped-columns-order}) {
--#{$prefix}table-color-type: var(--#{$prefix}table-striped-color);
--#{$prefix}table-bg-type: var(--#{$prefix}table-striped-bg);
}
}
@ -113,8 +129,8 @@
// The `.table-active` class can be added to highlight rows or cells
.table-active {
--#{$variable-prefix}table-accent-bg: var(--#{$variable-prefix}table-active-bg);
color: var(--#{$variable-prefix}table-active-color);
--#{$prefix}table-color-state: var(--#{$prefix}table-active-color);
--#{$prefix}table-bg-state: var(--#{$prefix}table-active-bg);
}
// Hover effect
@ -123,8 +139,8 @@
.table-hover {
> tbody > tr:hover > * {
--#{$variable-prefix}table-accent-bg: var(--#{$variable-prefix}table-hover-bg);
color: var(--#{$variable-prefix}table-hover-color);
--#{$prefix}table-color-state: var(--#{$prefix}table-hover-color);
--#{$prefix}table-bg-state: var(--#{$prefix}table-hover-bg);
}
}

View file

@ -1,14 +1,32 @@
.toast {
width: $toast-max-width;
// scss-docs-start toast-css-vars
--#{$prefix}toast-zindex: #{$zindex-toast};
--#{$prefix}toast-padding-x: #{$toast-padding-x};
--#{$prefix}toast-padding-y: #{$toast-padding-y};
--#{$prefix}toast-spacing: #{$toast-spacing};
--#{$prefix}toast-max-width: #{$toast-max-width};
@include rfs($toast-font-size, --#{$prefix}toast-font-size);
--#{$prefix}toast-color: #{$toast-color};
--#{$prefix}toast-bg: #{$toast-background-color};
--#{$prefix}toast-border-width: #{$toast-border-width};
--#{$prefix}toast-border-color: #{$toast-border-color};
--#{$prefix}toast-border-radius: #{$toast-border-radius};
--#{$prefix}toast-box-shadow: #{$toast-box-shadow};
--#{$prefix}toast-header-color: #{$toast-header-color};
--#{$prefix}toast-header-bg: #{$toast-header-background-color};
--#{$prefix}toast-header-border-color: #{$toast-header-border-color};
// scss-docs-end toast-css-vars
width: var(--#{$prefix}toast-max-width);
max-width: 100%;
@include font-size($toast-font-size);
color: $toast-color;
@include font-size(var(--#{$prefix}toast-font-size));
color: var(--#{$prefix}toast-color);
pointer-events: auto;
background-color: $toast-background-color;
background-color: var(--#{$prefix}toast-bg);
background-clip: padding-box;
border: $toast-border-width solid $toast-border-color;
box-shadow: $toast-box-shadow;
@include border-radius($toast-border-radius);
border: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-border-color);
box-shadow: var(--#{$prefix}toast-box-shadow);
@include border-radius(var(--#{$prefix}toast-border-radius));
&.showing {
opacity: 0;
@ -20,32 +38,36 @@
}
.toast-container {
--#{$prefix}toast-zindex: #{$zindex-toast};
position: absolute;
z-index: var(--#{$prefix}toast-zindex);
width: max-content;
max-width: 100%;
pointer-events: none;
> :not(:last-child) {
margin-bottom: $toast-spacing;
margin-bottom: var(--#{$prefix}toast-spacing);
}
}
.toast-header {
display: flex;
align-items: center;
padding: $toast-padding-y $toast-padding-x;
color: $toast-header-color;
background-color: $toast-header-background-color;
padding: var(--#{$prefix}toast-padding-y) var(--#{$prefix}toast-padding-x);
color: var(--#{$prefix}toast-header-color);
background-color: var(--#{$prefix}toast-header-bg);
background-clip: padding-box;
border-bottom: $toast-border-width solid $toast-header-border-color;
@include border-top-radius(subtract($toast-border-radius, $toast-border-width));
border-bottom: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-header-border-color);
@include border-top-radius(calc(var(--#{$prefix}toast-border-radius) - var(--#{$prefix}toast-border-width)));
.btn-close {
margin-right: $toast-padding-x * -.5;
margin-left: $toast-padding-x;
margin-right: calc(-.5 * var(--#{$prefix}toast-padding-x)); // stylelint-disable-line function-disallowed-list
margin-left: var(--#{$prefix}toast-padding-x);
}
}
.toast-body {
padding: $toast-padding-x; // apply to both vertical and horizontal
padding: var(--#{$prefix}toast-padding-x);
word-wrap: break-word;
}

View file

@ -1,24 +1,38 @@
// Base class
.tooltip {
position: absolute;
z-index: $zindex-tooltip;
// scss-docs-start tooltip-css-vars
--#{$prefix}tooltip-zindex: #{$zindex-tooltip};
--#{$prefix}tooltip-max-width: #{$tooltip-max-width};
--#{$prefix}tooltip-padding-x: #{$tooltip-padding-x};
--#{$prefix}tooltip-padding-y: #{$tooltip-padding-y};
--#{$prefix}tooltip-margin: #{$tooltip-margin};
@include rfs($tooltip-font-size, --#{$prefix}tooltip-font-size);
--#{$prefix}tooltip-color: #{$tooltip-color};
--#{$prefix}tooltip-bg: #{$tooltip-bg};
--#{$prefix}tooltip-border-radius: #{$tooltip-border-radius};
--#{$prefix}tooltip-opacity: #{$tooltip-opacity};
--#{$prefix}tooltip-arrow-width: #{$tooltip-arrow-width};
--#{$prefix}tooltip-arrow-height: #{$tooltip-arrow-height};
// scss-docs-end tooltip-css-vars
z-index: var(--#{$prefix}tooltip-zindex);
display: block;
margin: $tooltip-margin;
margin: var(--#{$prefix}tooltip-margin);
@include deprecate("`$tooltip-margin`", "v5", "v5.x", true);
// Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
// So reset our font and text properties to avoid inheriting weird values.
@include reset-text();
@include font-size($tooltip-font-size);
@include font-size(var(--#{$prefix}tooltip-font-size));
// Allow breaking very long words so they don't overflow the tooltip's bounds
word-wrap: break-word;
opacity: 0;
&.show { opacity: $tooltip-opacity; }
&.show { opacity: var(--#{$prefix}tooltip-opacity); }
.tooltip-arrow {
position: absolute;
display: block;
width: $tooltip-arrow-width;
height: $tooltip-arrow-height;
width: var(--#{$prefix}tooltip-arrow-width);
height: var(--#{$prefix}tooltip-arrow-height);
&::before {
position: absolute;
@ -29,66 +43,56 @@
}
}
.bs-tooltip-top {
padding: $tooltip-arrow-height 0;
.bs-tooltip-top .tooltip-arrow {
bottom: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list
.tooltip-arrow {
bottom: 0;
&::before {
top: -1px;
border-width: $tooltip-arrow-height ($tooltip-arrow-width * .5) 0;
border-top-color: $tooltip-arrow-color;
}
&::before {
top: -1px;
border-width: var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
border-top-color: var(--#{$prefix}tooltip-bg);
}
}
.bs-tooltip-end {
padding: 0 $tooltip-arrow-height;
/* rtl:begin:ignore */
.bs-tooltip-end .tooltip-arrow {
left: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list
width: var(--#{$prefix}tooltip-arrow-height);
height: var(--#{$prefix}tooltip-arrow-width);
.tooltip-arrow {
left: 0;
width: $tooltip-arrow-height;
height: $tooltip-arrow-width;
&::before {
right: -1px;
border-width: ($tooltip-arrow-width * .5) $tooltip-arrow-height ($tooltip-arrow-width * .5) 0;
border-right-color: $tooltip-arrow-color;
}
&::before {
right: -1px;
border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
border-right-color: var(--#{$prefix}tooltip-bg);
}
}
.bs-tooltip-bottom {
padding: $tooltip-arrow-height 0;
/* rtl:end:ignore */
.tooltip-arrow {
top: 0;
.bs-tooltip-bottom .tooltip-arrow {
top: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list
&::before {
bottom: -1px;
border-width: 0 ($tooltip-arrow-width * .5) $tooltip-arrow-height;
border-bottom-color: $tooltip-arrow-color;
}
&::before {
bottom: -1px;
border-width: 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list
border-bottom-color: var(--#{$prefix}tooltip-bg);
}
}
.bs-tooltip-start {
padding: 0 $tooltip-arrow-height;
/* rtl:begin:ignore */
.bs-tooltip-start .tooltip-arrow {
right: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list
width: var(--#{$prefix}tooltip-arrow-height);
height: var(--#{$prefix}tooltip-arrow-width);
.tooltip-arrow {
right: 0;
width: $tooltip-arrow-height;
height: $tooltip-arrow-width;
&::before {
left: -1px;
border-width: ($tooltip-arrow-width * .5) 0 ($tooltip-arrow-width * .5) $tooltip-arrow-height;
border-left-color: $tooltip-arrow-color;
}
&::before {
left: -1px;
border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list
border-left-color: var(--#{$prefix}tooltip-bg);
}
}
/* rtl:end:ignore */
.bs-tooltip-auto {
&[data-popper-placement^="top"] {
@extend .bs-tooltip-top;
@ -106,10 +110,10 @@
// Wrapper for the tooltip content
.tooltip-inner {
max-width: $tooltip-max-width;
padding: $tooltip-padding-y $tooltip-padding-x;
color: $tooltip-color;
max-width: var(--#{$prefix}tooltip-max-width);
padding: var(--#{$prefix}tooltip-padding-y) var(--#{$prefix}tooltip-padding-x);
color: var(--#{$prefix}tooltip-color);
text-align: center;
background-color: $tooltip-bg;
@include border-radius($tooltip-border-radius);
background-color: var(--#{$prefix}tooltip-bg);
@include border-radius(var(--#{$prefix}tooltip-border-radius));
}

View file

@ -35,6 +35,8 @@
@each $display, $font-size in $display-font-sizes {
.display-#{$display} {
@include font-size($font-size);
font-family: $display-font-family;
font-style: $display-font-style;
font-weight: $display-font-weight;
line-height: $display-line-height;
}

View file

@ -1,5 +1,3 @@
// stylelint-disable indentation
// Utilities
$utilities: () !default;
@ -24,6 +22,20 @@ $utilities: map-merge(
)
),
// scss-docs-end utils-float
// Object Fit utilities
// scss-docs-start utils-object-fit
"object-fit": (
responsive: true,
property: object-fit,
values: (
contain: contain,
cover: cover,
fill: fill,
scale: scale-down,
none: none,
)
),
// scss-docs-end utils-object-fit
// Opacity utilities
// scss-docs-start utils-opacity
"opacity": (
@ -42,6 +54,14 @@ $utilities: map-merge(
property: overflow,
values: auto hidden visible scroll,
),
"overflow-x": (
property: overflow-x,
values: auto hidden visible scroll,
),
"overflow-y": (
property: overflow-y,
values: auto hidden visible scroll,
),
// scss-docs-end utils-overflow
// scss-docs-start utils-display
"display": (
@ -49,7 +69,7 @@ $utilities: map-merge(
print: true,
property: display,
class: d,
values: inline inline-block block grid table table-row table-cell flex inline-flex none
values: inline inline-block block grid inline-grid table table-row table-cell flex inline-flex none
),
// scss-docs-end utils-display
// scss-docs-start utils-shadow
@ -57,13 +77,21 @@ $utilities: map-merge(
property: box-shadow,
class: shadow,
values: (
null: $box-shadow,
sm: $box-shadow-sm,
lg: $box-shadow-lg,
null: var(--#{$prefix}box-shadow),
sm: var(--#{$prefix}box-shadow-sm),
lg: var(--#{$prefix}box-shadow-lg),
none: none,
)
),
// scss-docs-end utils-shadow
// scss-docs-start utils-focus-ring
"focus-ring": (
css-var: true,
css-variable-name: focus-ring-color,
class: focus-ring,
values: map-loop($theme-colors-rgb, rgba-css-var, "$key", "focus-ring")
),
// scss-docs-end utils-focus-ring
// scss-docs-start utils-position
"position": (
property: position,
@ -101,14 +129,14 @@ $utilities: map-merge(
"border": (
property: border,
values: (
null: $border-width solid $border-color,
null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color),
0: 0,
)
),
"border-top": (
property: border-top,
values: (
null: $border-width solid $border-color,
null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color),
0: 0,
)
),
@ -116,14 +144,14 @@ $utilities: map-merge(
property: border-right,
class: border-end,
values: (
null: $border-width solid $border-color,
null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color),
0: 0,
)
),
"border-bottom": (
property: border-bottom,
values: (
null: $border-width solid $border-color,
null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color),
0: 0,
)
),
@ -131,20 +159,39 @@ $utilities: map-merge(
property: border-left,
class: border-start,
values: (
null: $border-width solid $border-color,
null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color),
0: 0,
)
),
"border-color": (
property: border-color,
class: border,
values: map-merge($theme-colors, ("white": $white))
local-vars: (
"border-opacity": 1
),
values: $utilities-border-colors
),
"subtle-border-color": (
property: border-color,
class: border,
values: $utilities-border-subtle
),
"border-width": (
property: border-width,
class: border,
values: $border-widths
),
"border-opacity": (
css-var: true,
class: border-opacity,
values: (
10: .1,
25: .25,
50: .5,
75: .75,
100: 1
)
),
// scss-docs-end utils-borders
// Sizing utilities
// scss-docs-start utils-sizing
@ -238,12 +285,6 @@ $utilities: map-merge(
class: flex,
values: wrap nowrap wrap-reverse
),
"gap": (
responsive: true,
property: gap,
class: gap,
values: $spacers
),
"justify-content": (
responsive: true,
property: justify-content,
@ -436,13 +477,32 @@ $utilities: map-merge(
class: ps,
values: $spacers
),
// Gap utility
"gap": (
responsive: true,
property: gap,
class: gap,
values: $spacers
),
"row-gap": (
responsive: true,
property: row-gap,
class: row-gap,
values: $spacers
),
"column-gap": (
responsive: true,
property: column-gap,
class: column-gap,
values: $spacers
),
// scss-docs-end utils-spacing
// Text
// scss-docs-start utils-text
"font-family": (
property: font-family,
class: font,
values: (monospace: var(--#{$variable-prefix}font-monospace))
values: (monospace: var(--#{$prefix}font-monospace))
),
"font-size": (
rfs: true,
@ -459,9 +519,11 @@ $utilities: map-merge(
property: font-weight,
class: fw,
values: (
light: $font-weight-light,
lighter: $font-weight-lighter,
light: $font-weight-light,
normal: $font-weight-normal,
medium: $font-weight-medium,
semibold: $font-weight-semibold,
bold: $font-weight-bold,
bolder: $font-weight-bolder
)
@ -520,9 +582,12 @@ $utilities: map-merge(
values: map-merge(
$utilities-text-colors,
(
"muted": $text-muted,
"muted": var(--#{$prefix}secondary-color), // deprecated
"black-50": rgba($black, .5), // deprecated
"white-50": rgba($white, .5), // deprecated
"body-secondary": var(--#{$prefix}secondary-color),
"body-tertiary": var(--#{$prefix}tertiary-color),
"body-emphasis": var(--#{$prefix}emphasis-color),
"reset": inherit,
)
)
@ -537,7 +602,62 @@ $utilities: map-merge(
100: 1
)
),
"text-color": (
property: color,
class: text,
values: $utilities-text-emphasis-colors
),
// scss-docs-end utils-color
// scss-docs-start utils-links
"link-opacity": (
css-var: true,
class: link-opacity,
state: hover,
values: (
10: .1,
25: .25,
50: .5,
75: .75,
100: 1
)
),
"link-offset": (
property: text-underline-offset,
class: link-offset,
state: hover,
values: (
1: .125em,
2: .25em,
3: .375em,
)
),
"link-underline": (
property: text-decoration-color,
class: link-underline,
local-vars: (
"link-underline-opacity": 1
),
values: map-merge(
$utilities-links-underline,
(
null: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-underline-opacity, 1)),
)
)
),
"link-underline-opacity": (
css-var: true,
class: link-underline-opacity,
state: hover,
values: (
0: 0,
10: .1,
25: .25,
50: .5,
75: .75,
100: 1
),
),
// scss-docs-end utils-links
// scss-docs-start utils-bg-color
"background-color": (
property: background-color,
@ -548,7 +668,9 @@ $utilities: map-merge(
values: map-merge(
$utilities-bg-colors,
(
"transparent": transparent
"transparent": transparent,
"body-secondary": rgba(var(--#{$prefix}secondary-bg-rgb), var(--#{$prefix}bg-opacity)),
"body-tertiary": rgba(var(--#{$prefix}tertiary-bg-rgb), var(--#{$prefix}bg-opacity)),
)
)
),
@ -563,11 +685,16 @@ $utilities: map-merge(
100: 1
)
),
"subtle-background-color": (
property: background-color,
class: bg,
values: $utilities-bg-subtle
),
// scss-docs-end utils-bg-color
"gradient": (
property: background-image,
class: bg,
values: (gradient: var(--#{$variable-prefix}gradient))
values: (gradient: var(--#{$prefix}gradient))
),
// scss-docs-start utils-interaction
"user-select": (
@ -585,34 +712,76 @@ $utilities: map-merge(
property: border-radius,
class: rounded,
values: (
null: $border-radius,
null: var(--#{$prefix}border-radius),
0: 0,
1: $border-radius-sm,
2: $border-radius,
3: $border-radius-lg,
1: var(--#{$prefix}border-radius-sm),
2: var(--#{$prefix}border-radius),
3: var(--#{$prefix}border-radius-lg),
4: var(--#{$prefix}border-radius-xl),
5: var(--#{$prefix}border-radius-xxl),
circle: 50%,
pill: $border-radius-pill
pill: var(--#{$prefix}border-radius-pill)
)
),
"rounded-top": (
property: border-top-left-radius border-top-right-radius,
class: rounded-top,
values: (null: $border-radius)
values: (
null: var(--#{$prefix}border-radius),
0: 0,
1: var(--#{$prefix}border-radius-sm),
2: var(--#{$prefix}border-radius),
3: var(--#{$prefix}border-radius-lg),
4: var(--#{$prefix}border-radius-xl),
5: var(--#{$prefix}border-radius-xxl),
circle: 50%,
pill: var(--#{$prefix}border-radius-pill)
)
),
"rounded-end": (
property: border-top-right-radius border-bottom-right-radius,
class: rounded-end,
values: (null: $border-radius)
values: (
null: var(--#{$prefix}border-radius),
0: 0,
1: var(--#{$prefix}border-radius-sm),
2: var(--#{$prefix}border-radius),
3: var(--#{$prefix}border-radius-lg),
4: var(--#{$prefix}border-radius-xl),
5: var(--#{$prefix}border-radius-xxl),
circle: 50%,
pill: var(--#{$prefix}border-radius-pill)
)
),
"rounded-bottom": (
property: border-bottom-right-radius border-bottom-left-radius,
class: rounded-bottom,
values: (null: $border-radius)
values: (
null: var(--#{$prefix}border-radius),
0: 0,
1: var(--#{$prefix}border-radius-sm),
2: var(--#{$prefix}border-radius),
3: var(--#{$prefix}border-radius-lg),
4: var(--#{$prefix}border-radius-xl),
5: var(--#{$prefix}border-radius-xxl),
circle: 50%,
pill: var(--#{$prefix}border-radius-pill)
)
),
"rounded-start": (
property: border-bottom-left-radius border-top-left-radius,
class: rounded-start,
values: (null: $border-radius)
values: (
null: var(--#{$prefix}border-radius),
0: 0,
1: var(--#{$prefix}border-radius-sm),
2: var(--#{$prefix}border-radius),
3: var(--#{$prefix}border-radius-lg),
4: var(--#{$prefix}border-radius-xl),
5: var(--#{$prefix}border-radius-xxl),
circle: 50%,
pill: var(--#{$prefix}border-radius-pill)
)
),
// scss-docs-end utils-border-radius
// scss-docs-start utils-visibility
@ -623,8 +792,15 @@ $utilities: map-merge(
visible: visible,
invisible: hidden,
)
)
),
// scss-docs-end utils-visibility
// scss-docs-start utils-zindex
"z-index": (
property: z-index,
class: z,
values: $zindex-levels,
)
// scss-docs-end utils-zindex
),
$utilities
);

View file

@ -0,0 +1,87 @@
// Dark color mode variables
//
// Custom variables for the `[data-bs-theme="dark"]` theme. Use this as a starting point for your own custom color modes by creating a new theme-specific file like `_variables-dark.scss` and adding the variables you need.
//
// Global colors
//
// scss-docs-start sass-dark-mode-vars
// scss-docs-start theme-text-dark-variables
$primary-text-emphasis-dark: tint-color($primary, 40%) !default;
$secondary-text-emphasis-dark: tint-color($secondary, 40%) !default;
$success-text-emphasis-dark: tint-color($success, 40%) !default;
$info-text-emphasis-dark: tint-color($info, 40%) !default;
$warning-text-emphasis-dark: tint-color($warning, 40%) !default;
$danger-text-emphasis-dark: tint-color($danger, 40%) !default;
$light-text-emphasis-dark: $gray-100 !default;
$dark-text-emphasis-dark: $gray-300 !default;
// scss-docs-end theme-text-dark-variables
// scss-docs-start theme-bg-subtle-dark-variables
$primary-bg-subtle-dark: shade-color($primary, 80%) !default;
$secondary-bg-subtle-dark: shade-color($secondary, 80%) !default;
$success-bg-subtle-dark: shade-color($success, 80%) !default;
$info-bg-subtle-dark: shade-color($info, 80%) !default;
$warning-bg-subtle-dark: shade-color($warning, 80%) !default;
$danger-bg-subtle-dark: shade-color($danger, 80%) !default;
$light-bg-subtle-dark: $gray-800 !default;
$dark-bg-subtle-dark: mix($gray-800, $black) !default;
// scss-docs-end theme-bg-subtle-dark-variables
// scss-docs-start theme-border-subtle-dark-variables
$primary-border-subtle-dark: shade-color($primary, 40%) !default;
$secondary-border-subtle-dark: shade-color($secondary, 40%) !default;
$success-border-subtle-dark: shade-color($success, 40%) !default;
$info-border-subtle-dark: shade-color($info, 40%) !default;
$warning-border-subtle-dark: shade-color($warning, 40%) !default;
$danger-border-subtle-dark: shade-color($danger, 40%) !default;
$light-border-subtle-dark: $gray-700 !default;
$dark-border-subtle-dark: $gray-800 !default;
// scss-docs-end theme-border-subtle-dark-variables
$body-color-dark: $gray-300 !default;
$body-bg-dark: $gray-900 !default;
$body-secondary-color-dark: rgba($body-color-dark, .75) !default;
$body-secondary-bg-dark: $gray-800 !default;
$body-tertiary-color-dark: rgba($body-color-dark, .5) !default;
$body-tertiary-bg-dark: mix($gray-800, $gray-900, 50%) !default;
$body-emphasis-color-dark: $white !default;
$border-color-dark: $gray-700 !default;
$border-color-translucent-dark: rgba($white, .15) !default;
$headings-color-dark: inherit !default;
$link-color-dark: tint-color($primary, 40%) !default;
$link-hover-color-dark: shift-color($link-color-dark, -$link-shade-percentage) !default;
$code-color-dark: tint-color($code-color, 40%) !default;
$mark-color-dark: $body-color-dark !default;
$mark-bg-dark: $yellow-800 !default;
//
// Forms
//
$form-select-indicator-color-dark: $body-color-dark !default;
$form-select-indicator-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='#{$form-select-indicator-color-dark}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/></svg>") !default;
$form-switch-color-dark: rgba($white, .25) !default;
$form-switch-bg-image-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-color-dark}'/></svg>") !default;
// scss-docs-start form-validation-colors-dark
$form-valid-color-dark: $green-300 !default;
$form-valid-border-color-dark: $green-300 !default;
$form-invalid-color-dark: $red-300 !default;
$form-invalid-border-color-dark: $red-300 !default;
// scss-docs-end form-validation-colors-dark
//
// Accordion
//
$accordion-icon-color-dark: $primary-text-emphasis-dark !default;
$accordion-icon-active-color-dark: $primary-text-emphasis-dark !default;
$accordion-button-icon-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-color-dark}'><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-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-active-color-dark}'><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;
// scss-docs-end sass-dark-mode-vars

View file

@ -1,16 +1,13 @@
/*!
* Bootstrap Grid v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
@import "mixins/banner";
@include bsBanner(Grid);
$include-column-box-sizing: true !default;
@import "functions";
@import "variables";
@import "variables-dark";
@import "maps";
@import "mixins/lists";
@import "mixins/breakpoints";
@import "mixins/container";
@import "mixins/grid";
@ -18,8 +15,6 @@ $include-column-box-sizing: true !default;
@import "vendor/rfs";
@import "root";
@import "containers";
@import "grid";

View file

@ -1,13 +1,10 @@
/*!
* Bootstrap Reboot v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
@import "mixins/banner";
@include bsBanner(Reboot);
@import "functions";
@import "variables";
@import "variables-dark";
@import "maps";
@import "mixins";
@import "root";
@import "reboot";

View file

@ -1,16 +1,17 @@
/*!
* Bootstrap Utilities v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
@import "mixins/banner";
@include bsBanner(Utilities);
// Configuration
@import "functions";
@import "variables";
@import "variables-dark";
@import "maps";
@import "mixins";
@import "utilities";
// Layout & components
@import "root";
// Helpers
@import "helpers";

View file

@ -1,14 +1,13 @@
/*!
* Bootstrap v5.1.3 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
@import "mixins/banner";
@include bsBanner("");
// scss-docs-start import-stack
// Configuration
@import "functions";
@import "variables";
@import "variables-dark";
@import "maps";
@import "mixins";
@import "utilities";

View file

@ -2,8 +2,10 @@
position: relative;
> .form-control,
> .form-control-plaintext,
> .form-select {
height: $form-floating-height;
min-height: $form-floating-height;
line-height: $form-floating-line-height;
}
@ -11,16 +13,21 @@
position: absolute;
top: 0;
left: 0;
z-index: 2;
height: 100%; // allow textareas
padding: $form-floating-padding-y $form-floating-padding-x;
overflow: hidden;
text-align: start;
text-overflow: ellipsis;
white-space: nowrap;
pointer-events: none;
border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model
transform-origin: 0 0;
@include transition($form-floating-transition);
}
// stylelint-disable no-duplicate-selectors
> .form-control {
> .form-control,
> .form-control-plaintext {
padding: $form-floating-padding-y $form-floating-padding-x;
&::placeholder {
@ -46,18 +53,43 @@
> .form-control:focus,
> .form-control:not(:placeholder-shown),
> .form-control-plaintext,
> .form-select {
~ label {
opacity: $form-floating-label-opacity;
color: rgba(var(--#{$prefix}body-color-rgb), #{$form-floating-label-opacity});
transform: $form-floating-label-transform;
&::after {
position: absolute;
inset: $form-floating-padding-y ($form-floating-padding-x * .5);
z-index: -1;
height: $form-floating-label-height;
content: "";
background-color: $input-bg;
@include border-radius($input-border-radius);
}
}
}
// Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
> .form-control:-webkit-autofill {
~ label {
opacity: $form-floating-label-opacity;
color: rgba(var(--#{$prefix}body-color-rgb), #{$form-floating-label-opacity});
transform: $form-floating-label-transform;
}
}
// stylelint-enable no-duplicate-selectors
> .form-control-plaintext {
~ label {
border-width: $input-border-width 0; // Required to properly position label text - as explained above
}
}
> :disabled ~ label,
> .form-control:disabled ~ label { // Required for `.form-control`s because of specificity
color: $form-floating-label-disabled-color;
&::after {
background-color: $input-disabled-bg;
}
}
}

View file

@ -14,18 +14,34 @@
}
}
.form-check-reverse {
padding-right: $form-check-padding-start;
padding-left: 0;
text-align: right;
.form-check-input {
float: right;
margin-right: $form-check-padding-start * -1;
margin-left: 0;
}
}
.form-check-input {
--#{$prefix}form-check-bg: #{$form-check-input-bg};
flex-shrink: 0;
width: $form-check-input-width;
height: $form-check-input-width;
margin-top: ($line-height-base - $form-check-input-width) * .5; // line-height minus check height
vertical-align: top;
background-color: $form-check-input-bg;
appearance: none;
background-color: var(--#{$prefix}form-check-bg);
background-image: var(--#{$prefix}form-check-bg-image);
background-repeat: no-repeat;
background-position: center;
background-size: contain;
border: $form-check-input-border;
appearance: none;
color-adjust: exact; // Keep themed appearance for print
print-color-adjust: exact; // Keep themed appearance for print
@include transition($form-check-transition);
&[type="checkbox"] {
@ -53,17 +69,17 @@
&[type="checkbox"] {
@if $enable-gradients {
background-image: escape-svg($form-check-input-checked-bg-image), var(--#{$variable-prefix}gradient);
--#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-checked-bg-image)}, var(--#{$prefix}gradient);
} @else {
background-image: escape-svg($form-check-input-checked-bg-image);
--#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-checked-bg-image)};
}
}
&[type="radio"] {
@if $enable-gradients {
background-image: escape-svg($form-check-radio-checked-bg-image), var(--#{$variable-prefix}gradient);
--#{$prefix}form-check-bg-image: #{escape-svg($form-check-radio-checked-bg-image)}, var(--#{$prefix}gradient);
} @else {
background-image: escape-svg($form-check-radio-checked-bg-image);
--#{$prefix}form-check-bg-image: #{escape-svg($form-check-radio-checked-bg-image)};
}
}
}
@ -73,9 +89,9 @@
border-color: $form-check-input-indeterminate-border-color;
@if $enable-gradients {
background-image: escape-svg($form-check-input-indeterminate-bg-image), var(--#{$variable-prefix}gradient);
--#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-indeterminate-bg-image)}, var(--#{$prefix}gradient);
} @else {
background-image: escape-svg($form-check-input-indeterminate-bg-image);
--#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-indeterminate-bg-image)};
}
}
@ -90,6 +106,7 @@
&[disabled],
&:disabled {
~ .form-check-label {
cursor: default;
opacity: $form-check-label-disabled-opacity;
}
}
@ -108,27 +125,39 @@
padding-left: $form-switch-padding-start;
.form-check-input {
--#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image)};
width: $form-switch-width;
margin-left: $form-switch-padding-start * -1;
background-image: escape-svg($form-switch-bg-image);
background-image: var(--#{$prefix}form-switch-bg);
background-position: left center;
@include border-radius($form-switch-border-radius);
@include border-radius($form-switch-border-radius, 0);
@include transition($form-switch-transition);
&:focus {
background-image: escape-svg($form-switch-focus-bg-image);
--#{$prefix}form-switch-bg: #{escape-svg($form-switch-focus-bg-image)};
}
&:checked {
background-position: $form-switch-checked-bg-position;
@if $enable-gradients {
background-image: escape-svg($form-switch-checked-bg-image), var(--#{$variable-prefix}gradient);
--#{$prefix}form-switch-bg: #{escape-svg($form-switch-checked-bg-image)}, var(--#{$prefix}gradient);
} @else {
background-image: escape-svg($form-switch-checked-bg-image);
--#{$prefix}form-switch-bg: #{escape-svg($form-switch-checked-bg-image)};
}
}
}
&.form-check-reverse {
padding-right: $form-switch-padding-start;
padding-left: 0;
.form-check-input {
margin-right: $form-switch-padding-start * -1;
margin-left: 0;
}
}
}
.form-check-inline {
@ -150,3 +179,11 @@
}
}
}
@if $enable-dark-mode {
@include color-mode(dark) {
.form-switch .form-check-input:not(:checked):not(:focus) {
--#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image-dark)};
}
}
}

View file

@ -11,10 +11,10 @@
font-weight: $input-font-weight;
line-height: $input-line-height;
color: $input-color;
appearance: none; // Fix appearance for date inputs in Safari
background-color: $input-bg;
background-clip: padding-box;
border: $input-border-width solid $input-border-color;
appearance: none; // Fix appearance for date inputs in Safari
// Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS.
@include border-radius($input-border-radius, 0);
@ -44,12 +44,31 @@
}
}
// Add some height to date inputs on iOS
// https://github.com/twbs/bootstrap/issues/23307
// TODO: we can remove this workaround once https://bugs.webkit.org/show_bug.cgi?id=198959 is resolved
&::-webkit-date-and-time-value {
// On Android Chrome, form-control's "width: 100%" makes the input width too small
// Tested under Android 11 / Chrome 89, Android 12 / Chrome 100, Android 13 / Chrome 109
//
// On iOS Safari, form-control's "appearance: none" + "width: 100%" makes the input width too small
// Tested under iOS 16.2 / Safari 16.2
min-width: 85px; // Seems to be a good minimum safe width
// Add some height to date inputs on iOS
// https://github.com/twbs/bootstrap/issues/23307
// TODO: we can remove this workaround once https://bugs.webkit.org/show_bug.cgi?id=198959 is resolved
// Multiply line-height by 1em if it has no unit
height: if(unit($input-line-height) == "", $input-line-height * 1em, $input-line-height);
// Android Chrome type="date" is taller than the other inputs
// because of "margin: 1px 24px 1px 4px" inside the shadow DOM
// Tested under Android 11 / Chrome 89, Android 12 / Chrome 100, Android 13 / Chrome 109
margin: 0;
}
// Prevent excessive date input height in Webkit
// https://github.com/twbs/bootstrap/issues/34433
&::-webkit-datetime-edit {
display: block;
padding: 0;
}
// Placeholder
@ -59,13 +78,13 @@
opacity: 1;
}
// Disabled and read-only inputs
// Disabled inputs
//
// HTML5 says that controls under a fieldset > legend:first-child won't be
// disabled if the fieldset is disabled. Due to implementation difficulty, we
// don't honor that edge case; we style them as disabled anyway.
&:disabled,
&[readonly] {
&:disabled {
color: $input-disabled-color;
background-color: $input-disabled-bg;
border-color: $input-disabled-border-color;
// iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655.
@ -91,25 +110,6 @@
&:hover:not(:disabled):not([readonly])::file-selector-button {
background-color: $form-file-button-hover-bg;
}
&::-webkit-file-upload-button {
padding: $input-padding-y $input-padding-x;
margin: (-$input-padding-y) (-$input-padding-x);
margin-inline-end: $input-padding-x;
color: $form-file-button-color;
@include gradient-bg($form-file-button-bg);
pointer-events: none;
border-color: inherit;
border-style: solid;
border-width: 0;
border-inline-end-width: $input-border-width;
border-radius: 0; // stylelint-disable-line property-disallowed-list
@include transition($btn-transition);
}
&:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {
background-color: $form-file-button-hover-bg;
}
}
// Readonly controls as plain text
@ -128,6 +128,10 @@
border: solid transparent;
border-width: $input-border-width 0;
&:focus {
outline: 0;
}
&.form-control-sm,
&.form-control-lg {
padding-right: 0;
@ -153,12 +157,6 @@
margin: (-$input-padding-y-sm) (-$input-padding-x-sm);
margin-inline-end: $input-padding-x-sm;
}
&::-webkit-file-upload-button {
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;
}
}
.form-control-lg {
@ -172,12 +170,6 @@
margin: (-$input-padding-y-lg) (-$input-padding-x-lg);
margin-inline-end: $input-padding-x-lg;
}
&::-webkit-file-upload-button {
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;
}
}
// Make sure textareas don't shrink too much when resized
@ -200,7 +192,7 @@ textarea {
.form-control-color {
width: $form-color-width;
height: auto; // Override fixed browser height
height: $input-height;
padding: $input-padding-y;
&:not(:disabled):not([readonly]) {
@ -208,12 +200,15 @@ textarea {
}
&::-moz-color-swatch {
height: if(unit($input-line-height) == "", $input-line-height * 1em, $input-line-height);
border: 0 !important; // stylelint-disable-line declaration-no-important
@include border-radius($input-border-radius);
}
&::-webkit-color-swatch {
height: if(unit($input-line-height) == "", $input-line-height * 1em, $input-line-height);
border: 0 !important; // stylelint-disable-line declaration-no-important
@include border-radius($input-border-radius);
}
&.form-control-sm { height: $input-height-sm; }
&.form-control-lg { height: $input-height-lg; }
}

View file

@ -8,8 +8,8 @@
width: 100%;
height: add($form-range-thumb-height, $form-range-thumb-focus-box-shadow-width * 2);
padding: 0; // Need to reset padding
background-color: transparent;
appearance: none;
background-color: transparent;
&:focus {
outline: 0;
@ -28,12 +28,12 @@
width: $form-range-thumb-width;
height: $form-range-thumb-height;
margin-top: ($form-range-track-height - $form-range-thumb-height) * .5; // Webkit specific
appearance: none;
@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);
@ -54,12 +54,12 @@
&::-moz-range-thumb {
width: $form-range-thumb-width;
height: $form-range-thumb-height;
appearance: none;
@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);

View file

@ -4,18 +4,19 @@
// https://primer.github.io/.
.form-select {
--#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator)};
display: block;
width: 100%;
padding: $form-select-padding-y $form-select-indicator-padding $form-select-padding-y $form-select-padding-x;
// stylelint-disable-next-line property-no-vendor-prefix
-moz-padding-start: subtract($form-select-padding-x, 3px); // See https://github.com/twbs/bootstrap/issues/32636
font-family: $form-select-font-family;
@include font-size($form-select-font-size);
font-weight: $form-select-font-weight;
line-height: $form-select-line-height;
color: $form-select-color;
appearance: none;
background-color: $form-select-bg;
background-image: escape-svg($form-select-indicator);
background-image: var(--#{$prefix}form-select-bg-img), var(--#{$prefix}form-select-bg-icon, none);
background-repeat: no-repeat;
background-position: $form-select-bg-position;
background-size: $form-select-bg-size;
@ -23,7 +24,6 @@
@include border-radius($form-select-border-radius, 0);
@include box-shadow($form-select-box-shadow);
@include transition($form-select-transition);
appearance: none;
&:focus {
border-color: $form-select-focus-border-color;
@ -70,3 +70,11 @@
@include font-size($form-select-font-size-lg);
@include border-radius($form-select-border-radius-lg);
}
@if $enable-dark-mode {
@include color-mode(dark) {
.form-select {
--#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator-dark)};
}
}
}

View file

@ -10,7 +10,8 @@
width: 100%;
> .form-control,
> .form-select {
> .form-select,
> .form-floating {
position: relative; // For focus state's z-index
flex: 1 1 auto;
width: 1%;
@ -19,8 +20,9 @@
// Bring the "active" form control to the top of surrounding elements
> .form-control:focus,
> .form-select:focus {
z-index: 3;
> .form-select:focus,
> .form-floating:focus-within {
z-index: 5;
}
// Ensure buttons are always above inputs for more visually pleasing borders.
@ -31,7 +33,7 @@
z-index: 2;
&:focus {
z-index: 3;
z-index: 5;
}
}
}
@ -96,15 +98,19 @@
// stylelint-disable-next-line no-duplicate-selectors
.input-group {
&:not(.has-validation) {
> :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu),
> .dropdown-toggle:nth-last-child(n + 3) {
> :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),
> .dropdown-toggle:nth-last-child(n + 3),
> .form-floating:not(:last-child) > .form-control,
> .form-floating:not(:last-child) > .form-select {
@include border-end-radius(0);
}
}
&.has-validation {
> :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu),
> .dropdown-toggle:nth-last-child(n + 4) {
> :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),
> .dropdown-toggle:nth-last-child(n + 4),
> .form-floating:nth-last-child(n + 3) > .form-control,
> .form-floating:nth-last-child(n + 3) > .form-select {
@include border-end-radius(0);
}
}
@ -115,7 +121,12 @@
}
> :not(:first-child):not(.dropdown-menu)#{$validation-messages} {
margin-left: -$input-border-width;
margin-left: calc(#{$input-border-width} * -1); // stylelint-disable-line function-disallowed-list
@include border-start-radius(0);
}
> .form-floating:not(:first-child) > .form-control,
> .form-floating:not(:first-child) > .form-select {
@include border-start-radius(0);
}
}

View file

@ -0,0 +1,7 @@
// All-caps `RGBA()` function used because of this Sass bug: https://github.com/sass/node-sass/issues/2251
@each $color, $value in $theme-colors {
.text-bg-#{$color} {
color: color-contrast($value) if($enable-important-utilities, !important, null);
background-color: RGBA(var(--#{$prefix}#{$color}-rgb), var(--#{$prefix}bg-opacity, 1)) if($enable-important-utilities, !important, null);
}
}

View file

@ -1,12 +1,30 @@
// All-caps `RGBA()` function used because of this Sass bug: https://github.com/sass/node-sass/issues/2251
@each $color, $value in $theme-colors {
.link-#{$color} {
color: $value;
color: RGBA(var(--#{$prefix}#{$color}-rgb), var(--#{$prefix}link-opacity, 1)) if($enable-important-utilities, !important, null);
text-decoration-color: RGBA(var(--#{$prefix}#{$color}-rgb), var(--#{$prefix}link-underline-opacity, 1)) if($enable-important-utilities, !important, null);
@if $link-shade-percentage != 0 {
&:hover,
&:focus {
color: if(color-contrast($value) == $color-contrast-light, shade-color($value, $link-shade-percentage), tint-color($value, $link-shade-percentage));
$hover-color: if(color-contrast($value) == $color-contrast-light, shade-color($value, $link-shade-percentage), tint-color($value, $link-shade-percentage));
color: RGBA(#{to-rgb($hover-color)}, var(--#{$prefix}link-opacity, 1)) if($enable-important-utilities, !important, null);
text-decoration-color: RGBA(to-rgb($hover-color), var(--#{$prefix}link-underline-opacity, 1)) if($enable-important-utilities, !important, null);
}
}
}
}
// One-off special link helper as a bridge until v6
.link-body-emphasis {
color: RGBA(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}link-opacity, 1)) if($enable-important-utilities, !important, null);
text-decoration-color: RGBA(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}link-underline-opacity, 1)) if($enable-important-utilities, !important, null);
@if $link-shade-percentage != 0 {
&:hover,
&:focus {
color: RGBA(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}link-opacity, .75)) if($enable-important-utilities, !important, null);
text-decoration-color: RGBA(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}link-underline-opacity, .75)) if($enable-important-utilities, !important, null);
}
}
}

View file

@ -0,0 +1,5 @@
.focus-ring:focus {
outline: 0;
// By default, there is no `--bs-focus-ring-x`, `--bs-focus-ring-y`, or `--bs-focus-ring-blur`, but we provide CSS variables with fallbacks to initial `0` values
box-shadow: var(--#{$prefix}focus-ring-x, 0) var(--#{$prefix}focus-ring-y, 0) var(--#{$prefix}focus-ring-blur, 0) var(--#{$prefix}focus-ring-width) var(--#{$prefix}focus-ring-color);
}

View file

@ -0,0 +1,25 @@
.icon-link {
display: inline-flex;
gap: $icon-link-gap;
align-items: center;
text-decoration-color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, .5));
text-underline-offset: $icon-link-underline-offset;
backface-visibility: hidden;
> .bi {
flex-shrink: 0;
width: $icon-link-icon-size;
height: $icon-link-icon-size;
fill: currentcolor;
@include transition($icon-link-icon-transition);
}
}
.icon-link-hover {
&:hover,
&:focus-visible {
> .bi {
transform: var(--#{$prefix}icon-link-transform, $icon-link-icon-transform);
}
}
}

View file

@ -16,7 +16,7 @@
z-index: $zindex-fixed;
}
// Responsive sticky top
// Responsive sticky top and bottom
@each $breakpoint in map-keys($grid-breakpoints) {
@include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
@ -26,5 +26,11 @@
top: 0;
z-index: $zindex-sticky;
}
.sticky#{$infix}-bottom {
position: sticky;
bottom: 0;
z-index: $zindex-sticky;
}
}
}

View file

@ -6,7 +6,7 @@
&::before {
display: block;
padding-top: var(--#{$variable-prefix}aspect-ratio);
padding-top: var(--#{$prefix}aspect-ratio);
content: "";
}
@ -21,6 +21,6 @@
@each $key, $ratio in $aspect-ratios {
.ratio-#{$key} {
--#{$variable-prefix}aspect-ratio: #{$ratio};
--#{$prefix}aspect-ratio: #{$ratio};
}
}

View file

@ -1,8 +1,8 @@
.vr {
display: inline-block;
align-self: stretch;
width: 1px;
width: $vr-border-width;
min-height: 1em;
background-color: currentColor;
background-color: currentcolor;
opacity: $hr-opacity;
}

View file

@ -1,11 +1,18 @@
@include deprecate("`alert-variant()`", "v5.3.0", "v6.0.0");
// scss-docs-start alert-variant-mixin
@mixin alert-variant($background, $border, $color) {
color: $color;
@include gradient-bg($background);
border-color: $border;
--#{$prefix}alert-color: #{$color};
--#{$prefix}alert-bg: #{$background};
--#{$prefix}alert-border-color: #{$border};
--#{$prefix}alert-link-color: #{shade-color($color, 20%)};
@if $enable-gradients {
background-image: var(--#{$prefix}gradient);
}
.alert-link {
color: shade-color($color, 20%);
color: var(--#{$prefix}alert-link-color);
}
}
// scss-docs-end alert-variant-mixin

View file

@ -0,0 +1,7 @@
@mixin bsBanner($file) {
/*!
* Bootstrap #{$file} v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
}

View file

@ -2,7 +2,7 @@
//
// Breakpoints are defined as a map of (name: minimum width), order from small to large:
//
// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)
// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)
//
// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.
@ -10,9 +10,9 @@
//
// >> breakpoint-next(sm)
// md
// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
// md
// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl))
// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl xxl))
// md
@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {
$n: index($breakpoint-names, $name);
@ -24,7 +24,7 @@
// Minimum breakpoint width. Null for the smallest (first) breakpoint.
//
// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
// 576px
@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {
$min: map-get($breakpoints, $name);
@ -38,7 +38,7 @@
// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.
// See https://bugs.webkit.org/show_bug.cgi?id=178261
//
// >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
// 767.98px
@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {
$max: map-get($breakpoints, $name);
@ -48,9 +48,9 @@
// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.
// Useful for making responsive utilities.
//
// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
// "" (Returns a blank string)
// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px))
// "-sm"
@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {
@return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}");
@ -109,7 +109,7 @@
@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {
$min: breakpoint-min($name, $breakpoints);
$next: breakpoint-next($name, $breakpoints);
$max: breakpoint-max($next);
$max: breakpoint-max($next, $breakpoints);
@if $min != null and $max != null {
@media (min-width: $min) and (max-width: $max) {

View file

@ -18,59 +18,20 @@
$disabled-border: $border,
$disabled-color: color-contrast($disabled-background)
) {
color: $color;
@include gradient-bg($background);
border-color: $border;
@include box-shadow($btn-box-shadow);
&:hover {
color: $hover-color;
@include gradient-bg($hover-background);
border-color: $hover-border;
}
.btn-check:focus + &,
&:focus {
color: $hover-color;
@include gradient-bg($hover-background);
border-color: $hover-border;
@if $enable-shadows {
@include box-shadow($btn-box-shadow, 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5));
} @else {
// Avoid using mixin so we can pass custom focus shadow properly
box-shadow: 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5);
}
}
.btn-check:checked + &,
.btn-check:active + &,
&:active,
&.active,
.show > &.dropdown-toggle {
color: $active-color;
background-color: $active-background;
// Remove CSS gradients if they're enabled
background-image: if($enable-gradients, none, null);
border-color: $active-border;
&:focus {
@if $enable-shadows {
@include box-shadow($btn-active-box-shadow, 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5));
} @else {
// Avoid using mixin so we can pass custom focus shadow properly
box-shadow: 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5);
}
}
}
&:disabled,
&.disabled {
color: $disabled-color;
background-color: $disabled-background;
// Remove CSS gradients if they're enabled
background-image: if($enable-gradients, none, null);
border-color: $disabled-border;
}
--#{$prefix}btn-color: #{$color};
--#{$prefix}btn-bg: #{$background};
--#{$prefix}btn-border-color: #{$border};
--#{$prefix}btn-hover-color: #{$hover-color};
--#{$prefix}btn-hover-bg: #{$hover-background};
--#{$prefix}btn-hover-border-color: #{$hover-border};
--#{$prefix}btn-focus-shadow-rgb: #{to-rgb(mix($color, $border, 15%))};
--#{$prefix}btn-active-color: #{$active-color};
--#{$prefix}btn-active-bg: #{$active-background};
--#{$prefix}btn-active-border-color: #{$active-border};
--#{$prefix}btn-active-shadow: #{$btn-active-box-shadow};
--#{$prefix}btn-disabled-color: #{$disabled-color};
--#{$prefix}btn-disabled-bg: #{$disabled-background};
--#{$prefix}btn-disabled-border-color: #{$disabled-border};
}
// scss-docs-end btn-variant-mixin
@ -82,52 +43,28 @@
$active-border: $color,
$active-color: color-contrast($active-background)
) {
color: $color;
border-color: $color;
&:hover {
color: $color-hover;
background-color: $active-background;
border-color: $active-border;
}
.btn-check:focus + &,
&:focus {
box-shadow: 0 0 0 $btn-focus-width rgba($color, .5);
}
.btn-check:checked + &,
.btn-check:active + &,
&:active,
&.active,
&.dropdown-toggle.show {
color: $active-color;
background-color: $active-background;
border-color: $active-border;
&:focus {
@if $enable-shadows {
@include box-shadow($btn-active-box-shadow, 0 0 0 $btn-focus-width rgba($color, .5));
} @else {
// Avoid using mixin so we can pass custom focus shadow properly
box-shadow: 0 0 0 $btn-focus-width rgba($color, .5);
}
}
}
&:disabled,
&.disabled {
color: $color;
background-color: transparent;
}
--#{$prefix}btn-color: #{$color};
--#{$prefix}btn-border-color: #{$color};
--#{$prefix}btn-hover-color: #{$color-hover};
--#{$prefix}btn-hover-bg: #{$active-background};
--#{$prefix}btn-hover-border-color: #{$active-border};
--#{$prefix}btn-focus-shadow-rgb: #{to-rgb($color)};
--#{$prefix}btn-active-color: #{$active-color};
--#{$prefix}btn-active-bg: #{$active-background};
--#{$prefix}btn-active-border-color: #{$active-border};
--#{$prefix}btn-active-shadow: #{$btn-active-box-shadow};
--#{$prefix}btn-disabled-color: #{$color};
--#{$prefix}btn-disabled-bg: transparent;
--#{$prefix}btn-disabled-border-color: #{$color};
--#{$prefix}gradient: none;
}
// scss-docs-end btn-outline-variant-mixin
// scss-docs-start btn-size-mixin
@mixin button-size($padding-y, $padding-x, $font-size, $border-radius) {
padding: $padding-y $padding-x;
@include font-size($font-size);
// Manually declare to provide an override to the browser default
@include border-radius($border-radius, 0);
--#{$prefix}btn-padding-y: #{$padding-y};
--#{$prefix}btn-padding-x: #{$padding-x};
@include rfs($font-size, --#{$prefix}btn-font-size);
--#{$prefix}btn-border-radius: #{$border-radius};
}
// scss-docs-end btn-size-mixin

View file

@ -1,44 +1,49 @@
// scss-docs-start caret-mixins
@mixin caret-down {
border-top: $caret-width solid;
border-right: $caret-width solid transparent;
@mixin caret-down($width: $caret-width) {
border-top: $width solid;
border-right: $width solid transparent;
border-bottom: 0;
border-left: $caret-width solid transparent;
border-left: $width solid transparent;
}
@mixin caret-up {
@mixin caret-up($width: $caret-width) {
border-top: 0;
border-right: $caret-width solid transparent;
border-bottom: $caret-width solid;
border-left: $caret-width solid transparent;
border-right: $width solid transparent;
border-bottom: $width solid;
border-left: $width solid transparent;
}
@mixin caret-end {
border-top: $caret-width solid transparent;
@mixin caret-end($width: $caret-width) {
border-top: $width solid transparent;
border-right: 0;
border-bottom: $caret-width solid transparent;
border-left: $caret-width solid;
border-bottom: $width solid transparent;
border-left: $width solid;
}
@mixin caret-start {
border-top: $caret-width solid transparent;
border-right: $caret-width solid;
border-bottom: $caret-width solid transparent;
@mixin caret-start($width: $caret-width) {
border-top: $width solid transparent;
border-right: $width solid;
border-bottom: $width solid transparent;
}
@mixin caret($direction: down) {
@mixin caret(
$direction: down,
$width: $caret-width,
$spacing: $caret-spacing,
$vertical-align: $caret-vertical-align
) {
@if $enable-caret {
&::after {
display: inline-block;
margin-left: $caret-spacing;
vertical-align: $caret-vertical-align;
margin-left: $spacing;
vertical-align: $vertical-align;
content: "";
@if $direction == down {
@include caret-down();
@include caret-down($width);
} @else if $direction == up {
@include caret-up();
@include caret-up($width);
} @else if $direction == end {
@include caret-end();
@include caret-end($width);
}
}
@ -49,10 +54,10 @@
&::before {
display: inline-block;
margin-right: $caret-spacing;
vertical-align: $caret-vertical-align;
margin-right: $spacing;
vertical-align: $vertical-align;
content: "";
@include caret-start();
@include caret-start($width);
}
}

View file

@ -0,0 +1,21 @@
// scss-docs-start color-mode-mixin
@mixin color-mode($mode: light, $root: false) {
@if $color-mode-type == "media-query" {
@if $root == true {
@media (prefers-color-scheme: $mode) {
:root {
@content;
}
}
} @else {
@media (prefers-color-scheme: $mode) {
@content;
}
}
} @else {
[data-bs-theme="#{$mode}"] {
@content;
}
}
}
// scss-docs-end color-mode-mixin

View file

@ -1,9 +1,11 @@
// Container mixins
@mixin make-container($gutter: $container-padding-x) {
--#{$prefix}gutter-x: #{$gutter};
--#{$prefix}gutter-y: 0;
width: 100%;
padding-right: var(--#{$variable-prefix}gutter-x, #{$gutter});
padding-left: var(--#{$variable-prefix}gutter-x, #{$gutter});
padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list
padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list
margin-right: auto;
margin-left: auto;
}

View file

@ -21,7 +21,8 @@
$icon,
$tooltip-color: color-contrast($color),
$tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity),
$focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity)
$focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity),
$border-color: $color
) {
.#{$state}-feedback {
display: none;
@ -56,7 +57,7 @@
.form-control {
@include form-validation-state-selector($state) {
border-color: $color;
border-color: $border-color;
@if $enable-validation-icons {
padding-right: $input-height-inner;
@ -67,8 +68,13 @@
}
&:focus {
border-color: $color;
box-shadow: $focus-box-shadow;
border-color: $border-color;
@if $enable-shadows {
@include box-shadow($input-box-shadow, $focus-box-shadow);
} @else {
// Avoid using mixin so we can pass custom focus shadow properly
box-shadow: $focus-box-shadow;
}
}
}
}
@ -85,28 +91,41 @@
.form-select {
@include form-validation-state-selector($state) {
border-color: $color;
border-color: $border-color;
@if $enable-validation-icons {
&:not([multiple]):not([size]),
&:not([multiple])[size="1"] {
--#{$prefix}form-select-bg-icon: #{escape-svg($icon)};
padding-right: $form-select-feedback-icon-padding-end;
background-image: escape-svg($form-select-indicator), escape-svg($icon);
background-position: $form-select-bg-position, $form-select-feedback-icon-position;
background-size: $form-select-bg-size, $form-select-feedback-icon-size;
}
}
&:focus {
border-color: $color;
box-shadow: $focus-box-shadow;
border-color: $border-color;
@if $enable-shadows {
@include box-shadow($form-select-box-shadow, $focus-box-shadow);
} @else {
// Avoid using mixin so we can pass custom focus shadow properly
box-shadow: $focus-box-shadow;
}
}
}
}
.form-control-color {
@include form-validation-state-selector($state) {
@if $enable-validation-icons {
width: add($form-color-width, $input-height-inner);
}
}
}
.form-check-input {
@include form-validation-state-selector($state) {
border-color: $color;
border-color: $border-color;
&:checked {
background-color: $color;
@ -127,16 +146,16 @@
}
}
.input-group .form-control,
.input-group .form-select {
@include form-validation-state-selector($state) {
@if $state == "valid" {
z-index: 1;
} @else if $state == "invalid" {
z-index: 2;
}
&:focus {
z-index: 3;
.input-group {
> .form-control:not(:focus),
> .form-select:not(:focus),
> .form-floating:not(:focus-within) {
@include form-validation-state-selector($state) {
@if $state == "valid" {
z-index: 3;
} @else if $state == "invalid" {
z-index: 4;
}
}
}
}

View file

@ -5,7 +5,7 @@
background-color: $color;
@if $enable-gradients {
background-image: var(--#{$variable-prefix}gradient);
background-image: var(--#{$prefix}gradient);
}
}
// scss-docs-end gradient-bg-mixin

View file

@ -3,17 +3,17 @@
// Generate semantic grid columns with these mixins.
@mixin make-row($gutter: $grid-gutter-width) {
--#{$variable-prefix}gutter-x: #{$gutter};
--#{$variable-prefix}gutter-y: 0;
--#{$prefix}gutter-x: #{$gutter};
--#{$prefix}gutter-y: 0;
display: flex;
flex-wrap: wrap;
// TODO: Revisit calc order after https://github.com/react-bootstrap/react-bootstrap/issues/6039 is fixed
margin-top: calc(-1 * var(--#{$variable-prefix}gutter-y)); // stylelint-disable-line function-disallowed-list
margin-right: calc(-.5 * var(--#{$variable-prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
margin-left: calc(-.5 * var(--#{$variable-prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
margin-top: calc(-1 * var(--#{$prefix}gutter-y)); // stylelint-disable-line function-disallowed-list
margin-right: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
margin-left: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
}
@mixin make-col-ready($gutter: $grid-gutter-width) {
@mixin make-col-ready() {
// Add box sizing if only the grid is loaded
box-sizing: if(variable-exists(include-column-box-sizing) and $include-column-box-sizing, border-box, null);
// Prevent columns from becoming too narrow when at smaller grid tiers by
@ -22,9 +22,9 @@
flex-shrink: 0;
width: 100%;
max-width: 100%; // Prevent `.col-auto`, `.col` (& responsive variants) from breaking out the grid
padding-right: calc(var(--#{$variable-prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list
padding-left: calc(var(--#{$variable-prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list
margin-top: var(--#{$variable-prefix}gutter-y);
padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list
padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list
margin-top: var(--#{$prefix}gutter-y);
}
@mixin make-col($size: false, $columns: $grid-columns) {
@ -51,12 +51,12 @@
// Row columns
//
// Specify on a parent element(e.g., .row) to force immediate children into NN
// numberof columns. Supports wrapping to new lines, but does not do a Masonry
// number of columns. Supports wrapping to new lines, but does not do a Masonry
// style grid.
@mixin row-cols($count) {
> * {
flex: 0 0 auto;
width: divide(100%, $count);
width: percentage(divide(1, $count));
}
}
@ -114,12 +114,12 @@
@each $key, $value in $gutters {
.g#{$infix}-#{$key},
.gx#{$infix}-#{$key} {
--#{$variable-prefix}gutter-x: #{$value};
--#{$prefix}gutter-x: #{$value};
}
.g#{$infix}-#{$key},
.gy#{$infix}-#{$key} {
--#{$variable-prefix}gutter-y: #{$value};
--#{$prefix}gutter-y: #{$value};
}
}
}
@ -138,7 +138,7 @@
}
}
// Start with `1` because `0` is and invalid value.
// Start with `1` because `0` is an invalid value.
// Ends with `$columns - 1` because offsetting by the width of an entire row isn't possible.
@for $i from 1 through ($columns - 1) {
.g-start#{$infix}-#{$i} {

View file

@ -1,3 +1,5 @@
@include deprecate("`list-group-item-variant()`", "v5.3.0", "v6.0.0");
// List Groups
// scss-docs-start list-group-mixin

View file

@ -2,30 +2,9 @@
// scss-docs-start pagination-mixin
@mixin pagination-size($padding-y, $padding-x, $font-size, $border-radius) {
.page-link {
padding: $padding-y $padding-x;
@include font-size($font-size);
}
.page-item {
@if $pagination-margin-start == (-$pagination-border-width) {
&:first-child {
.page-link {
@include border-start-radius($border-radius);
}
}
&:last-child {
.page-link {
@include border-end-radius($border-radius);
}
}
} @else {
//Add border-radius to all pageLinks in case they have left margin
.page-link {
@include border-radius($border-radius);
}
}
}
--#{$prefix}pagination-padding-x: #{$padding-x};
--#{$prefix}pagination-padding-y: #{$padding-y};
@include rfs($font-size, --#{$prefix}pagination-font-size);
--#{$prefix}pagination-border-radius: #{$border-radius};
}
// scss-docs-end pagination-mixin

View file

@ -11,7 +11,7 @@
text-transform: none;
letter-spacing: normal;
word-break: normal;
word-spacing: normal;
white-space: normal;
word-spacing: normal;
line-break: auto;
}

View file

@ -5,17 +5,20 @@
$hover-bg: mix($color, $background, percentage($table-hover-bg-factor));
$striped-bg: mix($color, $background, percentage($table-striped-bg-factor));
$active-bg: mix($color, $background, percentage($table-active-bg-factor));
$table-border-color: mix($color, $background, percentage($table-border-factor));
--#{$variable-prefix}table-bg: #{$background};
--#{$variable-prefix}table-striped-bg: #{$striped-bg};
--#{$variable-prefix}table-striped-color: #{color-contrast($striped-bg)};
--#{$variable-prefix}table-active-bg: #{$active-bg};
--#{$variable-prefix}table-active-color: #{color-contrast($active-bg)};
--#{$variable-prefix}table-hover-bg: #{$hover-bg};
--#{$variable-prefix}table-hover-color: #{color-contrast($hover-bg)};
--#{$prefix}table-color: #{$color};
--#{$prefix}table-bg: #{$background};
--#{$prefix}table-border-color: #{$table-border-color};
--#{$prefix}table-striped-bg: #{$striped-bg};
--#{$prefix}table-striped-color: #{color-contrast($striped-bg)};
--#{$prefix}table-active-bg: #{$active-bg};
--#{$prefix}table-active-color: #{color-contrast($active-bg)};
--#{$prefix}table-hover-bg: #{$hover-bg};
--#{$prefix}table-hover-color: #{color-contrast($hover-bg)};
color: $color;
border-color: mix($color, $background, percentage($table-border-factor));
color: var(--#{$prefix}table-color);
border-color: var(--#{$prefix}table-border-color);
}
}
// scss-docs-end table-variant

View file

@ -1,6 +1,6 @@
// Utility generator
// Used to generate utilities & print utilities
@mixin generate-utility($utility, $infix, $is-rfs-media-query: false) {
@mixin generate-utility($utility, $infix: "", $is-rfs-media-query: false) {
$values: map-get($utility, values);
// If the values are a list or string, convert it into a map
@ -20,12 +20,15 @@
$property-class: if(map-has-key($utility, class), map-get($utility, class), nth($properties, 1));
$property-class: if($property-class == null, "", $property-class);
// Use custom CSS variable name if present, otherwise default to `class`
$css-variable-name: if(map-has-key($utility, css-variable-name), map-get($utility, css-variable-name), map-get($utility, class));
// State params to generate pseudo-classes
$state: if(map-has-key($utility, state), map-get($utility, state), ());
$infix: if($property-class == "" and str-slice($infix, 1, 1) == "-", str-slice($infix, 2), $infix);
// Don't prefix if value key is null (eg. with shadow class)
// Don't prefix if value key is null (e.g. with shadow class)
$property-class-modifier: if($key, if($property-class == "" and $infix == "", "", "-") + $key, "");
@if map-get($utility, rfs) {
@ -52,20 +55,20 @@
@if $is-css-var {
.#{$property-class + $infix + $property-class-modifier} {
--#{$variable-prefix}#{$property-class}: #{$value};
--#{$prefix}#{$css-variable-name}: #{$value};
}
@each $pseudo in $state {
.#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {
--#{$variable-prefix}#{$property-class}: #{$value};
--#{$prefix}#{$css-variable-name}: #{$value};
}
}
} @else {
.#{$property-class + $infix + $property-class-modifier} {
@each $property in $properties {
@if $is-local-vars {
@each $local-var, $value in $is-local-vars {
--#{$variable-prefix}#{$local-var}: #{$value};
@each $local-var, $variable in $is-local-vars {
--#{$prefix}#{$local-var}: #{$variable};
}
}
#{$property}: $value if($enable-important-utilities, !important, null);
@ -75,6 +78,11 @@
@each $pseudo in $state {
.#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {
@each $property in $properties {
@if $is-local-vars {
@each $local-var, $variable in $is-local-vars {
--#{$prefix}#{$local-var}: #{$variable};
}
}
#{$property}: $value if($enable-important-utilities, !important, null);
}
}

View file

@ -6,7 +6,6 @@
// See: https://kittygiraudel.com/2016/10/13/css-hide-and-seek/
@mixin visually-hidden() {
position: absolute !important;
width: 1px !important;
height: 1px !important;
padding: 0 !important;
@ -15,6 +14,11 @@
clip: rect(0, 0, 0, 0) !important;
white-space: nowrap !important;
border: 0 !important;
// Fix for positioned table caption that could become anonymous cells
&:not(caption) {
position: absolute !important;
}
}
// Use to only display content when it's focused, or one of its child elements is focused

View file

@ -1,4 +1,4 @@
// stylelint-disable property-blacklist, scss/dollar-variable-default
// stylelint-disable scss/dimension-no-non-numeric-values
// SCSS RFS mixin
//
@ -154,8 +154,7 @@ $rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height
&.enable-rfs {
@content;
}
}
@else {
} @else {
@content;
}
}
@ -168,7 +167,7 @@ $rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height
@content;
}
@include _rfs-media-query {
@include _rfs-media-query () {
.enable-rfs &,
&.enable-rfs {
@content;
@ -182,7 +181,7 @@ $rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height
@content;
}
}
@include _rfs-media-query {
@include _rfs-media-query () {
@content;
}
}
@ -193,12 +192,12 @@ $rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height
// Convert to list
$values: if(type-of($values) != list, ($values,), $values);
$val: '';
$val: "";
// Loop over each value and calculate value
@each $value in $values {
@if $value == 0 {
$val: $val + ' 0';
$val: $val + " 0";
}
@else {
// Cache $value unit
@ -206,15 +205,14 @@ $rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height
@if $unit == px {
// Convert to rem if needed
$val: $val + ' ' + if($rfs-unit == rem, #{divide($value, $value * 0 + $rfs-rem-value)}rem, $value);
$val: $val + " " + if($rfs-unit == rem, #{divide($value, $value * 0 + $rfs-rem-value)}rem, $value);
}
@else if $unit == rem {
// Convert to px if needed
$val: $val + ' ' + if($rfs-unit == px, #{divide($value, $value * 0 + 1) * $rfs-rem-value}px, $value);
}
@else {
$val: $val + " " + if($rfs-unit == px, #{divide($value, $value * 0 + 1) * $rfs-rem-value}px, $value);
} @else {
// If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value
$val: $val + ' ' + $value;
$val: $val + " " + $value;
}
}
}
@ -228,30 +226,26 @@ $rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height
// Convert to list
$values: if(type-of($values) != list, ($values,), $values);
$val: '';
$val: "";
// Loop over each value and calculate value
@each $value in $values {
@if $value == 0 {
$val: $val + ' 0';
}
@else {
$val: $val + " 0";
} @else {
// Cache $value unit
$unit: if(type-of($value) == "number", unit($value), false);
// If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value
@if not $unit or $unit != px and $unit != rem {
$val: $val + ' ' + $value;
}
@else {
$val: $val + " " + $value;
} @else {
// Remove unit from $value for calculations
$value: divide($value, $value * 0 + if($unit == px, 1, divide(1, $rfs-rem-value)));
// Only add the media query if the value is greater than the minimum value
@if abs($value) <= $rfs-base-value or not $enable-rfs {
$val: $val + ' ' + if($rfs-unit == rem, #{divide($value, $rfs-rem-value)}rem, #{$value}px);
$val: $val + " " + if($rfs-unit == rem, #{divide($value, $rfs-rem-value)}rem, #{$value}px);
}
@else {
// Calculate the minimum value
@ -273,7 +267,7 @@ $rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height
$variable-width: #{divide($value-diff * 100, $rfs-breakpoint)}#{$variable-unit};
// Return the calculated value
$val: $val + ' calc(' + $min-width + if($value < 0, ' - ', ' + ') + $variable-width + ')';
$val: $val + " calc(" + $min-width + if($value < 0, " - ", " + ") + $variable-width + ")";
}
}
}
@ -287,22 +281,22 @@ $rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height
@mixin rfs($values, $property: font-size) {
@if $values != null {
$val: rfs-value($values);
$fluidVal: rfs-fluid-value($values);
$fluid-val: rfs-fluid-value($values);
// Do not print the media query if responsive & non-responsive values are the same
@if $val == $fluidVal {
@if $val == $fluid-val {
#{$property}: $val;
}
@else {
@include _rfs-rule {
#{$property}: if($rfs-mode == max-media-query, $val, $fluidVal);
@include _rfs-rule () {
#{$property}: if($rfs-mode == max-media-query, $val, $fluid-val);
// Include safari iframe resize fix if needed
min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null);
}
@include _rfs-media-query-rule {
#{$property}: if($rfs-mode == max-media-query, $fluidVal, $val);
@include _rfs-media-query-rule () {
#{$property}: if($rfs-mode == max-media-query, $fluid-val, $val);
}
}
}