Compare commits

..

4 Commits

Author SHA1 Message Date
Julien Déramond 8446581c3d Add new Sass mixins to the documentation 2025-09-04 22:34:24 +02:00
Julien Déramond 8915efae15 Fix docs compilation to avoid duplicate IDs 2025-09-04 22:30:39 +02:00
louismaxime.piton 72ee1af96a Proposal 2025-09-04 22:25:14 +02:00
Mark Otto f0700c7c3c Add option for always visible floating labels 2025-09-04 22:22:03 +02:00
338 changed files with 14264 additions and 14753 deletions
+8 -8
View File
@@ -2,35 +2,35 @@
"files": [
{
"path": "./dist/css/bootstrap-grid.css",
"maxSize": "7.75 kB"
"maxSize": "6.5 kB"
},
{
"path": "./dist/css/bootstrap-grid.min.css",
"maxSize": "6.75 kB"
"maxSize": "6.0 kB"
},
{
"path": "./dist/css/bootstrap-reboot.css",
"maxSize": "4.5 kB"
"maxSize": "3.5 kB"
},
{
"path": "./dist/css/bootstrap-reboot.min.css",
"maxSize": "4.5 kB"
"maxSize": "3.25 kB"
},
{
"path": "./dist/css/bootstrap-utilities.css",
"maxSize": "13.0 kB"
"maxSize": "11.75 kB"
},
{
"path": "./dist/css/bootstrap-utilities.min.css",
"maxSize": "12.0 kB"
"maxSize": "10.75 kB"
},
{
"path": "./dist/css/bootstrap.css",
"maxSize": "36.0 kB"
"maxSize": "32.5 kB"
},
{
"path": "./dist/css/bootstrap.min.css",
"maxSize": "32.0 kB"
"maxSize": "30.25 kB"
},
{
"path": "./dist/js/bootstrap.bundle.js",
-2
View File
@@ -21,7 +21,6 @@
"callout",
"callouts",
"camelCase",
"checkgroup",
"clearfix",
"Codesniffer",
"combinator",
@@ -30,7 +29,6 @@
"Crossfade",
"crossfading",
"cssgrid",
"csstricks",
"Csvg",
"Datalists",
"Deque",
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "${{ env.NODE }}"
cache: npm
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "${{ env.NODE }}"
cache: npm
@@ -27,6 +27,6 @@ jobs:
persist-credentials: false
- name: Compress Images
uses: calibreapp/image-actions@f32575787d333b0579f0b7d506ff03be63a669d1 # v1.4.1
uses: calibreapp/image-actions@f72c7c4a237181dd3b26e5935fd33b22ae4a7e26 # v1.4.0
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+3 -3
View File
@@ -29,16 +29,16 @@ jobs:
persist-credentials: false
- name: Initialize CodeQL
uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3
uses: github/codeql-action/init@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.30.0
with:
config-file: ./.github/codeql/codeql-config.yml
languages: "javascript"
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3
uses: github/codeql-action/autobuild@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.30.0
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3
uses: github/codeql-action/analyze@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.30.0
with:
category: "/language:javascript"
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "${{ env.NODE }}"
cache: npm
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "${{ env.NODE }}"
cache: npm
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: ${{ env.NODE }}
cache: npm
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "${{ env.NODE }}"
cache: npm
+49
View File
@@ -0,0 +1,49 @@
name: CSS (node-sass)
on:
push:
branches:
- main
pull_request:
workflow_dispatch:
env:
FORCE_COLOR: 2
NODE: 22
permissions:
contents: read
jobs:
css:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "${{ env.NODE }}"
- name: Build CSS with node-sass
run: |
npx --package node-sass@latest node-sass --version
npx --package node-sass@latest node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/ -o dist-sass/css/
ls -Al dist-sass/css
- name: Check built CSS files for Sass variables
shell: bash
run: |
SASS_VARS_FOUND=$(find "dist-sass/css/" -type f -name "*.css" -print0 | xargs -0 --no-run-if-empty grep -F "\$" || true)
if [[ -z "$SASS_VARS_FOUND" ]]; then
echo "All good, no Sass variables found!"
exit 0
else
echo "Found $(echo "$SASS_VARS_FOUND" | wc -l | bc) Sass variables:"
echo "$SASS_VARS_FOUND"
exit 1
fi
+1 -1
View File
@@ -73,6 +73,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3
uses: github/codeql-action/upload-sarif@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.30.0
with:
sarif_file: results.sarif
-18
View File
@@ -1,18 +0,0 @@
{
"default": true,
"MD004": { "style": "dash" },
"MD011": false,
"MD013": false,
"MD024": false,
"MD025": false,
"MD026": false,
"MD031": false,
"MD033": false,
"MD034": false,
"MD037": false,
"MD038": false,
"MD041": false,
"MD046": false,
"line-length": false,
"no-inline-html": false
}
+1
View File
@@ -13,6 +13,7 @@
"outline": "none"
},
"function-disallowed-list": [
"calc",
"lighten",
"darken"
],
+511 -206
View File
@@ -57,6 +57,252 @@
}
};
/**
* --------------------------------------------------------------------------
* 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$1 = 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$1(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$1(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.harrytheo.com/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.call(...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))];
};
/**
* --------------------------------------------------------------------------
* Bootstrap dom/event-handler.js
@@ -64,6 +310,7 @@
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
@@ -232,11 +479,33 @@
if (typeof event !== 'string' || !element) {
return null;
}
const $ = getjQuery();
const typeEvent = getTypeEvent(event);
const inNamespace = event !== typeEvent;
let jQueryEvent = null;
let bubbles = true;
let nativeDispatch = true;
let defaultPrevented = false;
if (inNamespace && $) {
jQueryEvent = $.Event(event, args);
$(element).trigger(jQueryEvent);
bubbles = !jQueryEvent.isPropagationStopped();
nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();
defaultPrevented = jQueryEvent.isDefaultPrevented();
}
const evt = hydrateObj(new Event(event, {
bubbles: true,
bubbles,
cancelable: true
}), args);
element.dispatchEvent(evt);
if (defaultPrevented) {
evt.preventDefault();
}
if (nativeDispatch) {
element.dispatchEvent(evt);
}
if (evt.defaultPrevented && jQueryEvent) {
jQueryEvent.preventDefault();
}
return evt;
}
};
@@ -313,210 +582,6 @@
}
};
/**
* --------------------------------------------------------------------------
* 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$1 = object => {
if (!object || typeof object !== 'object') {
return false;
}
return typeof object.nodeType !== 'undefined';
};
const getElement = object => {
if (isElement$1(object)) {
return object;
}
if (typeof object === 'string' && object.length > 0) {
return document.querySelector(parseSelector(object));
}
return null;
};
const isVisible = element => {
if (!isElement$1(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.harrytheo.com/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 isRTL = () => document.documentElement.dir === 'rtl';
const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {
return typeof possibleCallback === 'function' ? possibleCallback.call(...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))];
};
/**
* --------------------------------------------------------------------------
* Bootstrap util/config.js
@@ -802,6 +867,20 @@
EventHandler.trigger(this._element, EVENT_CLOSED);
this.dispose();
}
// 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);
});
}
}
/**
@@ -810,6 +889,12 @@
enableDismissTrigger(Alert, 'close');
/**
* jQuery
*/
defineJQueryPlugin(Alert);
/**
* --------------------------------------------------------------------------
* Bootstrap button.js
@@ -845,6 +930,16 @@
// 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$3));
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Button.getOrCreateInstance(this);
if (config === 'toggle') {
data[config]();
}
});
}
}
/**
@@ -858,6 +953,12 @@
data.toggle();
});
/**
* jQuery
*/
defineJQueryPlugin(Button);
/**
* --------------------------------------------------------------------------
* Bootstrap util/swipe.js
@@ -1294,6 +1395,23 @@
}
return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;
}
// Static
static jQueryInterface(config) {
return this.each(function () {
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]();
}
});
}
}
/**
@@ -1328,6 +1446,12 @@
}
});
/**
* jQuery
*/
defineJQueryPlugin(Carousel);
/**
* --------------------------------------------------------------------------
* Bootstrap collapse.js
@@ -1521,6 +1645,23 @@
element.setAttribute('aria-expanded', isOpen);
}
}
// Static
static jQueryInterface(config) {
const _config = {};
if (typeof config === 'string' && /show|hide/.test(config)) {
_config.toggle = false;
}
return this.each(function () {
const data = Collapse.getOrCreateInstance(this, _config);
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
}
});
}
}
/**
@@ -1539,6 +1680,12 @@
}
});
/**
* jQuery
*/
defineJQueryPlugin(Collapse);
var top = 'top';
var bottom = 'bottom';
var right = 'right';
@@ -3649,6 +3796,20 @@
// allow cycling to get the last item in case key equals ARROW_UP_KEY
getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus();
}
// 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.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1) {
return;
@@ -3724,6 +3885,12 @@
Dropdown.getOrCreateInstance(this).toggle();
});
/**
* jQuery
*/
defineJQueryPlugin(Dropdown);
/**
* --------------------------------------------------------------------------
* Bootstrap util/backdrop.js
@@ -4296,6 +4463,20 @@
this._element.style.paddingLeft = '';
this._element.style.paddingRight = '';
}
// Static
static jQueryInterface(config, relatedTarget) {
return this.each(function () {
const data = Modal.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config](relatedTarget);
});
}
}
/**
@@ -4329,6 +4510,12 @@
});
enableDismissTrigger(Modal);
/**
* jQuery
*/
defineJQueryPlugin(Modal);
/**
* --------------------------------------------------------------------------
* Bootstrap offcanvas.js
@@ -4497,6 +4684,20 @@
EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);
});
}
// 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);
});
}
}
/**
@@ -4540,6 +4741,12 @@
});
enableDismissTrigger(Offcanvas);
/**
* jQuery
*/
defineJQueryPlugin(Offcanvas);
/**
* --------------------------------------------------------------------------
* Bootstrap util/sanitizer.js
@@ -5261,8 +5468,28 @@
this.tip = null;
}
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Tooltip.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
* jQuery
*/
defineJQueryPlugin(Tooltip);
/**
* --------------------------------------------------------------------------
* Bootstrap popover.js
@@ -5322,8 +5549,28 @@
_getContent() {
return this._resolvePossibleFunction(this._config.content);
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Popover.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
* jQuery
*/
defineJQueryPlugin(Popover);
/**
* --------------------------------------------------------------------------
* Bootstrap scrollspy.js
@@ -5552,6 +5799,20 @@
node.classList.remove(CLASS_NAME_ACTIVE$1);
}
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = ScrollSpy.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]();
});
}
}
/**
@@ -5564,6 +5825,12 @@
}
});
/**
* jQuery
*/
defineJQueryPlugin(ScrollSpy);
/**
* --------------------------------------------------------------------------
* Bootstrap tab.js
@@ -5790,6 +6057,20 @@
_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') {
return;
}
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
@@ -5814,6 +6095,11 @@
Tab.getOrCreateInstance(element);
}
});
/**
* jQuery
*/
defineJQueryPlugin(Tab);
/**
* --------------------------------------------------------------------------
@@ -5971,6 +6257,19 @@
clearTimeout(this._timeout);
this._timeout = null;
}
// 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);
}
});
}
}
/**
@@ -5979,6 +6278,12 @@
enableDismissTrigger(Toast);
/**
* jQuery
*/
defineJQueryPlugin(Toast);
/**
* --------------------------------------------------------------------------
* Bootstrap index.umd.js
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+511 -206
View File
@@ -53,6 +53,252 @@ const Data = {
}
};
/**
* --------------------------------------------------------------------------
* 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.harrytheo.com/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.call(...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))];
};
/**
* --------------------------------------------------------------------------
* Bootstrap dom/event-handler.js
@@ -60,6 +306,7 @@ const Data = {
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
@@ -228,11 +475,33 @@ const EventHandler = {
if (typeof event !== 'string' || !element) {
return null;
}
const $ = getjQuery();
const typeEvent = getTypeEvent(event);
const inNamespace = event !== typeEvent;
let jQueryEvent = null;
let bubbles = true;
let nativeDispatch = true;
let defaultPrevented = false;
if (inNamespace && $) {
jQueryEvent = $.Event(event, args);
$(element).trigger(jQueryEvent);
bubbles = !jQueryEvent.isPropagationStopped();
nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();
defaultPrevented = jQueryEvent.isDefaultPrevented();
}
const evt = hydrateObj(new Event(event, {
bubbles: true,
bubbles,
cancelable: true
}), args);
element.dispatchEvent(evt);
if (defaultPrevented) {
evt.preventDefault();
}
if (nativeDispatch) {
element.dispatchEvent(evt);
}
if (evt.defaultPrevented && jQueryEvent) {
jQueryEvent.preventDefault();
}
return evt;
}
};
@@ -309,210 +578,6 @@ const Manipulator = {
}
};
/**
* --------------------------------------------------------------------------
* 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;
}
return typeof object.nodeType !== 'undefined';
};
const getElement = object => {
if (isElement(object)) {
return 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.harrytheo.com/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 isRTL = () => document.documentElement.dir === 'rtl';
const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {
return typeof possibleCallback === 'function' ? possibleCallback.call(...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))];
};
/**
* --------------------------------------------------------------------------
* Bootstrap util/config.js
@@ -798,6 +863,20 @@ class Alert extends BaseComponent {
EventHandler.trigger(this._element, EVENT_CLOSED);
this.dispose();
}
// 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);
});
}
}
/**
@@ -806,6 +885,12 @@ class Alert extends BaseComponent {
enableDismissTrigger(Alert, 'close');
/**
* jQuery
*/
defineJQueryPlugin(Alert);
/**
* --------------------------------------------------------------------------
* Bootstrap button.js
@@ -841,6 +926,16 @@ class Button extends BaseComponent {
// 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$3));
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Button.getOrCreateInstance(this);
if (config === 'toggle') {
data[config]();
}
});
}
}
/**
@@ -854,6 +949,12 @@ EventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$5, event
data.toggle();
});
/**
* jQuery
*/
defineJQueryPlugin(Button);
/**
* --------------------------------------------------------------------------
* Bootstrap util/swipe.js
@@ -1290,6 +1391,23 @@ class Carousel extends BaseComponent {
}
return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;
}
// Static
static jQueryInterface(config) {
return this.each(function () {
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]();
}
});
}
}
/**
@@ -1324,6 +1442,12 @@ EventHandler.on(window, EVENT_LOAD_DATA_API$3, () => {
}
});
/**
* jQuery
*/
defineJQueryPlugin(Carousel);
/**
* --------------------------------------------------------------------------
* Bootstrap collapse.js
@@ -1517,6 +1641,23 @@ class Collapse extends BaseComponent {
element.setAttribute('aria-expanded', isOpen);
}
}
// Static
static jQueryInterface(config) {
const _config = {};
if (typeof config === 'string' && /show|hide/.test(config)) {
_config.toggle = false;
}
return this.each(function () {
const data = Collapse.getOrCreateInstance(this, _config);
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
}
});
}
}
/**
@@ -1535,6 +1676,12 @@ EventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$4, functi
}
});
/**
* jQuery
*/
defineJQueryPlugin(Collapse);
/**
* --------------------------------------------------------------------------
* Bootstrap dropdown.js
@@ -1808,6 +1955,20 @@ class Dropdown extends BaseComponent {
// allow cycling to get the last item in case key equals ARROW_UP_KEY
getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus();
}
// 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.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1) {
return;
@@ -1883,6 +2044,12 @@ EventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, functi
Dropdown.getOrCreateInstance(this).toggle();
});
/**
* jQuery
*/
defineJQueryPlugin(Dropdown);
/**
* --------------------------------------------------------------------------
* Bootstrap util/backdrop.js
@@ -2455,6 +2622,20 @@ class Modal extends BaseComponent {
this._element.style.paddingLeft = '';
this._element.style.paddingRight = '';
}
// Static
static jQueryInterface(config, relatedTarget) {
return this.each(function () {
const data = Modal.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config](relatedTarget);
});
}
}
/**
@@ -2488,6 +2669,12 @@ EventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, functi
});
enableDismissTrigger(Modal);
/**
* jQuery
*/
defineJQueryPlugin(Modal);
/**
* --------------------------------------------------------------------------
* Bootstrap offcanvas.js
@@ -2656,6 +2843,20 @@ class Offcanvas extends BaseComponent {
EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);
});
}
// 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);
});
}
}
/**
@@ -2699,6 +2900,12 @@ EventHandler.on(window, EVENT_RESIZE, () => {
});
enableDismissTrigger(Offcanvas);
/**
* jQuery
*/
defineJQueryPlugin(Offcanvas);
/**
* --------------------------------------------------------------------------
* Bootstrap util/sanitizer.js
@@ -3420,8 +3627,28 @@ class Tooltip extends BaseComponent {
this.tip = null;
}
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Tooltip.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
* jQuery
*/
defineJQueryPlugin(Tooltip);
/**
* --------------------------------------------------------------------------
* Bootstrap popover.js
@@ -3481,8 +3708,28 @@ class Popover extends Tooltip {
_getContent() {
return this._resolvePossibleFunction(this._config.content);
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Popover.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
* jQuery
*/
defineJQueryPlugin(Popover);
/**
* --------------------------------------------------------------------------
* Bootstrap scrollspy.js
@@ -3711,6 +3958,20 @@ class ScrollSpy extends BaseComponent {
node.classList.remove(CLASS_NAME_ACTIVE$1);
}
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = ScrollSpy.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]();
});
}
}
/**
@@ -3723,6 +3984,12 @@ EventHandler.on(window, EVENT_LOAD_DATA_API$1, () => {
}
});
/**
* jQuery
*/
defineJQueryPlugin(ScrollSpy);
/**
* --------------------------------------------------------------------------
* Bootstrap tab.js
@@ -3949,6 +4216,20 @@ class Tab extends BaseComponent {
_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') {
return;
}
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
@@ -3973,6 +4254,11 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
Tab.getOrCreateInstance(element);
}
});
/**
* jQuery
*/
defineJQueryPlugin(Tab);
/**
* --------------------------------------------------------------------------
@@ -4130,6 +4416,19 @@ class Toast extends BaseComponent {
clearTimeout(this._timeout);
this._timeout = null;
}
// 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);
}
});
}
}
/**
@@ -4138,5 +4437,11 @@ class Toast extends BaseComponent {
enableDismissTrigger(Toast);
/**
* jQuery
*/
defineJQueryPlugin(Toast);
export { Alert, Button, Carousel, Collapse, Dropdown, Modal, Offcanvas, Popover, ScrollSpy, Tab, Toast, Tooltip };
//# sourceMappingURL=bootstrap.esm.js.map
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+511 -206
View File
@@ -76,6 +76,252 @@
}
};
/**
* --------------------------------------------------------------------------
* 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.harrytheo.com/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.call(...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))];
};
/**
* --------------------------------------------------------------------------
* Bootstrap dom/event-handler.js
@@ -83,6 +329,7 @@
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
@@ -251,11 +498,33 @@
if (typeof event !== 'string' || !element) {
return null;
}
const $ = getjQuery();
const typeEvent = getTypeEvent(event);
const inNamespace = event !== typeEvent;
let jQueryEvent = null;
let bubbles = true;
let nativeDispatch = true;
let defaultPrevented = false;
if (inNamespace && $) {
jQueryEvent = $.Event(event, args);
$(element).trigger(jQueryEvent);
bubbles = !jQueryEvent.isPropagationStopped();
nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();
defaultPrevented = jQueryEvent.isDefaultPrevented();
}
const evt = hydrateObj(new Event(event, {
bubbles: true,
bubbles,
cancelable: true
}), args);
element.dispatchEvent(evt);
if (defaultPrevented) {
evt.preventDefault();
}
if (nativeDispatch) {
element.dispatchEvent(evt);
}
if (evt.defaultPrevented && jQueryEvent) {
jQueryEvent.preventDefault();
}
return evt;
}
};
@@ -332,210 +601,6 @@
}
};
/**
* --------------------------------------------------------------------------
* 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;
}
return typeof object.nodeType !== 'undefined';
};
const getElement = object => {
if (isElement(object)) {
return 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.harrytheo.com/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 isRTL = () => document.documentElement.dir === 'rtl';
const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {
return typeof possibleCallback === 'function' ? possibleCallback.call(...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))];
};
/**
* --------------------------------------------------------------------------
* Bootstrap util/config.js
@@ -821,6 +886,20 @@
EventHandler.trigger(this._element, EVENT_CLOSED);
this.dispose();
}
// 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);
});
}
}
/**
@@ -829,6 +908,12 @@
enableDismissTrigger(Alert, 'close');
/**
* jQuery
*/
defineJQueryPlugin(Alert);
/**
* --------------------------------------------------------------------------
* Bootstrap button.js
@@ -864,6 +949,16 @@
// 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$3));
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Button.getOrCreateInstance(this);
if (config === 'toggle') {
data[config]();
}
});
}
}
/**
@@ -877,6 +972,12 @@
data.toggle();
});
/**
* jQuery
*/
defineJQueryPlugin(Button);
/**
* --------------------------------------------------------------------------
* Bootstrap util/swipe.js
@@ -1313,6 +1414,23 @@
}
return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;
}
// Static
static jQueryInterface(config) {
return this.each(function () {
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]();
}
});
}
}
/**
@@ -1347,6 +1465,12 @@
}
});
/**
* jQuery
*/
defineJQueryPlugin(Carousel);
/**
* --------------------------------------------------------------------------
* Bootstrap collapse.js
@@ -1540,6 +1664,23 @@
element.setAttribute('aria-expanded', isOpen);
}
}
// Static
static jQueryInterface(config) {
const _config = {};
if (typeof config === 'string' && /show|hide/.test(config)) {
_config.toggle = false;
}
return this.each(function () {
const data = Collapse.getOrCreateInstance(this, _config);
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
}
});
}
}
/**
@@ -1558,6 +1699,12 @@
}
});
/**
* jQuery
*/
defineJQueryPlugin(Collapse);
/**
* --------------------------------------------------------------------------
* Bootstrap dropdown.js
@@ -1831,6 +1978,20 @@
// allow cycling to get the last item in case key equals ARROW_UP_KEY
getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus();
}
// 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.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1) {
return;
@@ -1906,6 +2067,12 @@
Dropdown.getOrCreateInstance(this).toggle();
});
/**
* jQuery
*/
defineJQueryPlugin(Dropdown);
/**
* --------------------------------------------------------------------------
* Bootstrap util/backdrop.js
@@ -2478,6 +2645,20 @@
this._element.style.paddingLeft = '';
this._element.style.paddingRight = '';
}
// Static
static jQueryInterface(config, relatedTarget) {
return this.each(function () {
const data = Modal.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config](relatedTarget);
});
}
}
/**
@@ -2511,6 +2692,12 @@
});
enableDismissTrigger(Modal);
/**
* jQuery
*/
defineJQueryPlugin(Modal);
/**
* --------------------------------------------------------------------------
* Bootstrap offcanvas.js
@@ -2679,6 +2866,20 @@
EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);
});
}
// 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);
});
}
}
/**
@@ -2722,6 +2923,12 @@
});
enableDismissTrigger(Offcanvas);
/**
* jQuery
*/
defineJQueryPlugin(Offcanvas);
/**
* --------------------------------------------------------------------------
* Bootstrap util/sanitizer.js
@@ -3443,8 +3650,28 @@
this.tip = null;
}
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Tooltip.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
* jQuery
*/
defineJQueryPlugin(Tooltip);
/**
* --------------------------------------------------------------------------
* Bootstrap popover.js
@@ -3504,8 +3731,28 @@
_getContent() {
return this._resolvePossibleFunction(this._config.content);
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Popover.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
* jQuery
*/
defineJQueryPlugin(Popover);
/**
* --------------------------------------------------------------------------
* Bootstrap scrollspy.js
@@ -3734,6 +3981,20 @@
node.classList.remove(CLASS_NAME_ACTIVE$1);
}
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = ScrollSpy.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]();
});
}
}
/**
@@ -3746,6 +4007,12 @@
}
});
/**
* jQuery
*/
defineJQueryPlugin(ScrollSpy);
/**
* --------------------------------------------------------------------------
* Bootstrap tab.js
@@ -3972,6 +4239,20 @@
_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') {
return;
}
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
@@ -3996,6 +4277,11 @@
Tab.getOrCreateInstance(element);
}
});
/**
* jQuery
*/
defineJQueryPlugin(Tab);
/**
* --------------------------------------------------------------------------
@@ -4153,6 +4439,19 @@
clearTimeout(this._timeout);
this._timeout = null;
}
// 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);
}
});
}
}
/**
@@ -4161,6 +4460,12 @@
enableDismissTrigger(Toast);
/**
* jQuery
*/
defineJQueryPlugin(Toast);
/**
* --------------------------------------------------------------------------
* Bootstrap index.umd.js
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+24 -4
View File
@@ -4,10 +4,10 @@
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./util/component-functions.js')) :
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './util/component-functions'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Alert = factory(global.BaseComponent, global.EventHandler, global.ComponentFunctions));
})(this, (function (BaseComponent, EventHandler, componentFunctions_js) { 'use strict';
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';
/**
* --------------------------------------------------------------------------
@@ -56,6 +56,20 @@
EventHandler.trigger(this._element, EVENT_CLOSED);
this.dispose();
}
// 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);
});
}
}
/**
@@ -64,6 +78,12 @@
componentFunctions_js.enableDismissTrigger(Alert, 'close');
/**
* jQuery
*/
index_js.defineJQueryPlugin(Alert);
return Alert;
}));
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"alert.js","sources":["../src/alert.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\nexport default Alert\n"],"names":["NAME","DATA_KEY","EVENT_KEY","EVENT_CLOSE","EVENT_CLOSED","CLASS_NAME_FADE","CLASS_NAME_SHOW","Alert","BaseComponent","close","closeEvent","EventHandler","trigger","_element","defaultPrevented","classList","remove","isAnimated","contains","_queueCallback","_destroyElement","dispose","enableDismissTrigger"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;;EAMA;EACA;EACA;;EAEA,MAAMA,IAAI,GAAG,OAAO;EACpB,MAAMC,QAAQ,GAAG,UAAU;EAC3B,MAAMC,SAAS,GAAG,CAAA,CAAA,EAAID,QAAQ,CAAA,CAAE;EAEhC,MAAME,WAAW,GAAG,CAAA,KAAA,EAAQD,SAAS,CAAA,CAAE;EACvC,MAAME,YAAY,GAAG,CAAA,MAAA,EAASF,SAAS,CAAA,CAAE;EACzC,MAAMG,eAAe,GAAG,MAAM;EAC9B,MAAMC,eAAe,GAAG,MAAM;;EAE9B;EACA;EACA;;EAEA,MAAMC,KAAK,SAASC,aAAa,CAAC;EAChC;IACA,WAAWR,IAAIA,GAAG;EAChB,IAAA,OAAOA,IAAI;EACb,EAAA;;EAEA;EACAS,EAAAA,KAAKA,GAAG;MACN,MAAMC,UAAU,GAAGC,YAAY,CAACC,OAAO,CAAC,IAAI,CAACC,QAAQ,EAAEV,WAAW,CAAC;MAEnE,IAAIO,UAAU,CAACI,gBAAgB,EAAE;EAC/B,MAAA;EACF,IAAA;MAEA,IAAI,CAACD,QAAQ,CAACE,SAAS,CAACC,MAAM,CAACV,eAAe,CAAC;MAE/C,MAAMW,UAAU,GAAG,IAAI,CAACJ,QAAQ,CAACE,SAAS,CAACG,QAAQ,CAACb,eAAe,CAAC;EACpE,IAAA,IAAI,CAACc,cAAc,CAAC,MAAM,IAAI,CAACC,eAAe,EAAE,EAAE,IAAI,CAACP,QAAQ,EAAEI,UAAU,CAAC;EAC9E,EAAA;;EAEA;EACAG,EAAAA,eAAeA,GAAG;EAChB,IAAA,IAAI,CAACP,QAAQ,CAACG,MAAM,EAAE;MACtBL,YAAY,CAACC,OAAO,CAAC,IAAI,CAACC,QAAQ,EAAET,YAAY,CAAC;MACjD,IAAI,CAACiB,OAAO,EAAE;EAChB,EAAA;EACF;;EAEA;EACA;EACA;;AAEAC,4CAAoB,CAACf,KAAK,EAAE,OAAO,CAAC;;;;;;;;"}
{"version":3,"file":"alert.js","sources":["../src/alert.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n"],"names":["NAME","DATA_KEY","EVENT_KEY","EVENT_CLOSE","EVENT_CLOSED","CLASS_NAME_FADE","CLASS_NAME_SHOW","Alert","BaseComponent","close","closeEvent","EventHandler","trigger","_element","defaultPrevented","classList","remove","isAnimated","contains","_queueCallback","_destroyElement","dispose","jQueryInterface","config","each","data","getOrCreateInstance","undefined","startsWith","TypeError","enableDismissTrigger","defineJQueryPlugin"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;;EAOA;EACA;EACA;;EAEA,MAAMA,IAAI,GAAG,OAAO;EACpB,MAAMC,QAAQ,GAAG,UAAU;EAC3B,MAAMC,SAAS,GAAG,CAAA,CAAA,EAAID,QAAQ,CAAA,CAAE;EAEhC,MAAME,WAAW,GAAG,CAAA,KAAA,EAAQD,SAAS,CAAA,CAAE;EACvC,MAAME,YAAY,GAAG,CAAA,MAAA,EAASF,SAAS,CAAA,CAAE;EACzC,MAAMG,eAAe,GAAG,MAAM;EAC9B,MAAMC,eAAe,GAAG,MAAM;;EAE9B;EACA;EACA;;EAEA,MAAMC,KAAK,SAASC,aAAa,CAAC;EAChC;IACA,WAAWR,IAAIA,GAAG;EAChB,IAAA,OAAOA,IAAI;EACb,EAAA;;EAEA;EACAS,EAAAA,KAAKA,GAAG;MACN,MAAMC,UAAU,GAAGC,YAAY,CAACC,OAAO,CAAC,IAAI,CAACC,QAAQ,EAAEV,WAAW,CAAC;MAEnE,IAAIO,UAAU,CAACI,gBAAgB,EAAE;EAC/B,MAAA;EACF,IAAA;MAEA,IAAI,CAACD,QAAQ,CAACE,SAAS,CAACC,MAAM,CAACV,eAAe,CAAC;MAE/C,MAAMW,UAAU,GAAG,IAAI,CAACJ,QAAQ,CAACE,SAAS,CAACG,QAAQ,CAACb,eAAe,CAAC;EACpE,IAAA,IAAI,CAACc,cAAc,CAAC,MAAM,IAAI,CAACC,eAAe,EAAE,EAAE,IAAI,CAACP,QAAQ,EAAEI,UAAU,CAAC;EAC9E,EAAA;;EAEA;EACAG,EAAAA,eAAeA,GAAG;EAChB,IAAA,IAAI,CAACP,QAAQ,CAACG,MAAM,EAAE;MACtBL,YAAY,CAACC,OAAO,CAAC,IAAI,CAACC,QAAQ,EAAET,YAAY,CAAC;MACjD,IAAI,CAACiB,OAAO,EAAE;EAChB,EAAA;;EAEA;IACA,OAAOC,eAAeA,CAACC,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACC,IAAI,CAAC,YAAY;EAC3B,MAAA,MAAMC,IAAI,GAAGlB,KAAK,CAACmB,mBAAmB,CAAC,IAAI,CAAC;EAE5C,MAAA,IAAI,OAAOH,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA;EACF,MAAA;EAEA,MAAA,IAAIE,IAAI,CAACF,MAAM,CAAC,KAAKI,SAAS,IAAIJ,MAAM,CAACK,UAAU,CAAC,GAAG,CAAC,IAAIL,MAAM,KAAK,aAAa,EAAE;EACpF,QAAA,MAAM,IAAIM,SAAS,CAAC,CAAA,iBAAA,EAAoBN,MAAM,GAAG,CAAC;EACpD,MAAA;EAEAE,MAAAA,IAAI,CAACF,MAAM,CAAC,CAAC,IAAI,CAAC;EACpB,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;AAEAO,4CAAoB,CAACvB,KAAK,EAAE,OAAO,CAAC;;EAEpC;EACA;EACA;;AAEAwB,6BAAkB,CAACxB,KAAK,CAAC;;;;;;;;"}
+20 -4
View File
@@ -4,10 +4,10 @@
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js')) :
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Button = factory(global.BaseComponent, global.EventHandler));
})(this, (function (BaseComponent, EventHandler) { 'use strict';
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';
/**
* --------------------------------------------------------------------------
@@ -44,6 +44,16 @@
// 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 jQueryInterface(config) {
return this.each(function () {
const data = Button.getOrCreateInstance(this);
if (config === 'toggle') {
data[config]();
}
});
}
}
/**
@@ -57,6 +67,12 @@
data.toggle();
});
/**
* jQuery
*/
index_js.defineJQueryPlugin(Button);
return Button;
}));
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"button.js","sources":["../src/button.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\nexport default Button\n"],"names":["NAME","DATA_KEY","EVENT_KEY","DATA_API_KEY","CLASS_NAME_ACTIVE","SELECTOR_DATA_TOGGLE","EVENT_CLICK_DATA_API","Button","BaseComponent","toggle","_element","setAttribute","classList","EventHandler","on","document","event","preventDefault","button","target","closest","data","getOrCreateInstance"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;;EAKA;EACA;EACA;;EAEA,MAAMA,IAAI,GAAG,QAAQ;EACrB,MAAMC,QAAQ,GAAG,WAAW;EAC5B,MAAMC,SAAS,GAAG,CAAA,CAAA,EAAID,QAAQ,CAAA,CAAE;EAChC,MAAME,YAAY,GAAG,WAAW;EAEhC,MAAMC,iBAAiB,GAAG,QAAQ;EAClC,MAAMC,oBAAoB,GAAG,2BAA2B;EACxD,MAAMC,oBAAoB,GAAG,CAAA,KAAA,EAAQJ,SAAS,CAAA,EAAGC,YAAY,CAAA,CAAE;;EAE/D;EACA;EACA;;EAEA,MAAMI,MAAM,SAASC,aAAa,CAAC;EACjC;IACA,WAAWR,IAAIA,GAAG;EAChB,IAAA,OAAOA,IAAI;EACb,EAAA;;EAEA;EACAS,EAAAA,MAAMA,GAAG;EACP;EACA,IAAA,IAAI,CAACC,QAAQ,CAACC,YAAY,CAAC,cAAc,EAAE,IAAI,CAACD,QAAQ,CAACE,SAAS,CAACH,MAAM,CAACL,iBAAiB,CAAC,CAAC;EAC/F,EAAA;EACF;;EAEA;EACA;EACA;;EAEAS,YAAY,CAACC,EAAE,CAACC,QAAQ,EAAET,oBAAoB,EAAED,oBAAoB,EAAEW,KAAK,IAAI;IAC7EA,KAAK,CAACC,cAAc,EAAE;IAEtB,MAAMC,MAAM,GAAGF,KAAK,CAACG,MAAM,CAACC,OAAO,CAACf,oBAAoB,CAAC;EACzD,EAAA,MAAMgB,IAAI,GAAGd,MAAM,CAACe,mBAAmB,CAACJ,MAAM,CAAC;IAE/CG,IAAI,CAACZ,MAAM,EAAE;EACf,CAAC,CAAC;;;;;;;;"}
{"version":3,"file":"button.js","sources":["../src/button.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n"],"names":["NAME","DATA_KEY","EVENT_KEY","DATA_API_KEY","CLASS_NAME_ACTIVE","SELECTOR_DATA_TOGGLE","EVENT_CLICK_DATA_API","Button","BaseComponent","toggle","_element","setAttribute","classList","jQueryInterface","config","each","data","getOrCreateInstance","EventHandler","on","document","event","preventDefault","button","target","closest","defineJQueryPlugin"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;;EAMA;EACA;EACA;;EAEA,MAAMA,IAAI,GAAG,QAAQ;EACrB,MAAMC,QAAQ,GAAG,WAAW;EAC5B,MAAMC,SAAS,GAAG,CAAA,CAAA,EAAID,QAAQ,CAAA,CAAE;EAChC,MAAME,YAAY,GAAG,WAAW;EAEhC,MAAMC,iBAAiB,GAAG,QAAQ;EAClC,MAAMC,oBAAoB,GAAG,2BAA2B;EACxD,MAAMC,oBAAoB,GAAG,CAAA,KAAA,EAAQJ,SAAS,CAAA,EAAGC,YAAY,CAAA,CAAE;;EAE/D;EACA;EACA;;EAEA,MAAMI,MAAM,SAASC,aAAa,CAAC;EACjC;IACA,WAAWR,IAAIA,GAAG;EAChB,IAAA,OAAOA,IAAI;EACb,EAAA;;EAEA;EACAS,EAAAA,MAAMA,GAAG;EACP;EACA,IAAA,IAAI,CAACC,QAAQ,CAACC,YAAY,CAAC,cAAc,EAAE,IAAI,CAACD,QAAQ,CAACE,SAAS,CAACH,MAAM,CAACL,iBAAiB,CAAC,CAAC;EAC/F,EAAA;;EAEA;IACA,OAAOS,eAAeA,CAACC,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACC,IAAI,CAAC,YAAY;EAC3B,MAAA,MAAMC,IAAI,GAAGT,MAAM,CAACU,mBAAmB,CAAC,IAAI,CAAC;QAE7C,IAAIH,MAAM,KAAK,QAAQ,EAAE;EACvBE,QAAAA,IAAI,CAACF,MAAM,CAAC,EAAE;EAChB,MAAA;EACF,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;EAEAI,YAAY,CAACC,EAAE,CAACC,QAAQ,EAAEd,oBAAoB,EAAED,oBAAoB,EAAEgB,KAAK,IAAI;IAC7EA,KAAK,CAACC,cAAc,EAAE;IAEtB,MAAMC,MAAM,GAAGF,KAAK,CAACG,MAAM,CAACC,OAAO,CAACpB,oBAAoB,CAAC;EACzD,EAAA,MAAMW,IAAI,GAAGT,MAAM,CAACU,mBAAmB,CAACM,MAAM,CAAC;IAE/CP,IAAI,CAACP,MAAM,EAAE;EACf,CAAC,CAAC;;EAEF;EACA;EACA;;AAEAiB,6BAAkB,CAACnB,MAAM,CAAC;;;;;;;;"}
+23
View File
@@ -325,6 +325,23 @@
}
return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;
}
// Static
static jQueryInterface(config) {
return this.each(function () {
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]();
}
});
}
}
/**
@@ -359,6 +376,12 @@
}
});
/**
* jQuery
*/
index_js.defineJQueryPlugin(Carousel);
return Carousel;
}));
+1 -1
View File
File diff suppressed because one or more lines are too long
+23
View File
@@ -202,6 +202,23 @@
element.setAttribute('aria-expanded', isOpen);
}
}
// Static
static jQueryInterface(config) {
const _config = {};
if (typeof config === 'string' && /show|hide/.test(config)) {
_config.toggle = false;
}
return this.each(function () {
const data = Collapse.getOrCreateInstance(this, _config);
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
}
});
}
}
/**
@@ -220,6 +237,12 @@
}
});
/**
* jQuery
*/
index_js.defineJQueryPlugin(Collapse);
return Collapse;
}));
+1 -1
View File
File diff suppressed because one or more lines are too long
+29 -6
View File
@@ -4,10 +4,10 @@
* 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';
/**
* --------------------------------------------------------------------------
@@ -16,6 +16,7 @@
* --------------------------------------------------------------------------
*/
/**
* Constants
*/
@@ -184,11 +185,33 @@
if (typeof event !== 'string' || !element) {
return null;
}
const $ = index_js.getjQuery();
const typeEvent = getTypeEvent(event);
const inNamespace = event !== typeEvent;
let jQueryEvent = null;
let bubbles = true;
let nativeDispatch = true;
let defaultPrevented = false;
if (inNamespace && $) {
jQueryEvent = $.Event(event, args);
$(element).trigger(jQueryEvent);
bubbles = !jQueryEvent.isPropagationStopped();
nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();
defaultPrevented = jQueryEvent.isDefaultPrevented();
}
const evt = hydrateObj(new Event(event, {
bubbles: true,
bubbles,
cancelable: true
}), args);
element.dispatchEvent(evt);
if (defaultPrevented) {
evt.preventDefault();
}
if (nativeDispatch) {
element.dispatchEvent(evt);
}
if (evt.defaultPrevented && jQueryEvent) {
jQueryEvent.preventDefault();
}
return evt;
}
};
+1 -1
View File
File diff suppressed because one or more lines are too long
+20
View File
@@ -301,6 +301,20 @@
// 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();
}
// 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.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY) {
return;
@@ -376,6 +390,12 @@
Dropdown.getOrCreateInstance(this).toggle();
});
/**
* jQuery
*/
index_js.defineJQueryPlugin(Dropdown);
return Dropdown;
}));
+1 -1
View File
File diff suppressed because one or more lines are too long
+20
View File
@@ -261,6 +261,20 @@
this._element.style.paddingLeft = '';
this._element.style.paddingRight = '';
}
// Static
static jQueryInterface(config, relatedTarget) {
return this.each(function () {
const data = Modal.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config](relatedTarget);
});
}
}
/**
@@ -294,6 +308,12 @@
});
componentFunctions_js.enableDismissTrigger(Modal);
/**
* jQuery
*/
index_js.defineJQueryPlugin(Modal);
return Modal;
}));
+1 -1
View File
File diff suppressed because one or more lines are too long
+20
View File
@@ -177,6 +177,20 @@
EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);
});
}
// 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);
});
}
}
/**
@@ -220,6 +234,12 @@
});
componentFunctions_js.enableDismissTrigger(Offcanvas);
/**
* jQuery
*/
index_js.defineJQueryPlugin(Offcanvas);
return Offcanvas;
}));
+1 -1
View File
File diff suppressed because one or more lines are too long
+24 -4
View File
@@ -4,10 +4,10 @@
* 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';
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';
/**
* --------------------------------------------------------------------------
@@ -68,8 +68,28 @@
_getContent() {
return this._resolvePossibleFunction(this._config.content);
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Popover.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
* jQuery
*/
index_js.defineJQueryPlugin(Popover);
return Popover;
}));
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"popover.js","sources":["../src/popover.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n}\n\nexport default Popover\n"],"names":["NAME","SELECTOR_TITLE","SELECTOR_CONTENT","Default","Tooltip","content","offset","placement","template","trigger","DefaultType","Popover","_isWithContent","_getTitle","_getContent","_getContentForTemplate","_resolvePossibleFunction","_config"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;;EAIA;EACA;EACA;;EAEA,MAAMA,IAAI,GAAG,SAAS;EAEtB,MAAMC,cAAc,GAAG,iBAAiB;EACxC,MAAMC,gBAAgB,GAAG,eAAe;EAExC,MAAMC,OAAO,GAAG;IACd,GAAGC,OAAO,CAACD,OAAO;EAClBE,EAAAA,OAAO,EAAE,EAAE;EACXC,EAAAA,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;EACdC,EAAAA,SAAS,EAAE,OAAO;IAClBC,QAAQ,EAAE,sCAAsC,GAC9C,mCAAmC,GACnC,kCAAkC,GAClC,kCAAkC,GAClC,QAAQ;EACVC,EAAAA,OAAO,EAAE;EACX,CAAC;EAED,MAAMC,WAAW,GAAG;IAClB,GAAGN,OAAO,CAACM,WAAW;EACtBL,EAAAA,OAAO,EAAE;EACX,CAAC;;EAED;EACA;EACA;;EAEA,MAAMM,OAAO,SAASP,OAAO,CAAC;EAC5B;IACA,WAAWD,OAAOA,GAAG;EACnB,IAAA,OAAOA,OAAO;EAChB,EAAA;IAEA,WAAWO,WAAWA,GAAG;EACvB,IAAA,OAAOA,WAAW;EACpB,EAAA;IAEA,WAAWV,IAAIA,GAAG;EAChB,IAAA,OAAOA,IAAI;EACb,EAAA;;EAEA;EACAY,EAAAA,cAAcA,GAAG;MACf,OAAO,IAAI,CAACC,SAAS,EAAE,IAAI,IAAI,CAACC,WAAW,EAAE;EAC/C,EAAA;;EAEA;EACAC,EAAAA,sBAAsBA,GAAG;MACvB,OAAO;EACL,MAAA,CAACd,cAAc,GAAG,IAAI,CAACY,SAAS,EAAE;EAClC,MAAA,CAACX,gBAAgB,GAAG,IAAI,CAACY,WAAW;OACrC;EACH,EAAA;EAEAA,EAAAA,WAAWA,GAAG;MACZ,OAAO,IAAI,CAACE,wBAAwB,CAAC,IAAI,CAACC,OAAO,CAACZ,OAAO,CAAC;EAC5D,EAAA;EACF;;;;;;;;"}
{"version":3,"file":"popover.js","sources":["../src/popover.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n"],"names":["NAME","SELECTOR_TITLE","SELECTOR_CONTENT","Default","Tooltip","content","offset","placement","template","trigger","DefaultType","Popover","_isWithContent","_getTitle","_getContent","_getContentForTemplate","_resolvePossibleFunction","_config","jQueryInterface","config","each","data","getOrCreateInstance","TypeError","defineJQueryPlugin"],"mappings":";;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;;EAKA;EACA;EACA;;EAEA,MAAMA,IAAI,GAAG,SAAS;EAEtB,MAAMC,cAAc,GAAG,iBAAiB;EACxC,MAAMC,gBAAgB,GAAG,eAAe;EAExC,MAAMC,OAAO,GAAG;IACd,GAAGC,OAAO,CAACD,OAAO;EAClBE,EAAAA,OAAO,EAAE,EAAE;EACXC,EAAAA,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;EACdC,EAAAA,SAAS,EAAE,OAAO;IAClBC,QAAQ,EAAE,sCAAsC,GAC9C,mCAAmC,GACnC,kCAAkC,GAClC,kCAAkC,GAClC,QAAQ;EACVC,EAAAA,OAAO,EAAE;EACX,CAAC;EAED,MAAMC,WAAW,GAAG;IAClB,GAAGN,OAAO,CAACM,WAAW;EACtBL,EAAAA,OAAO,EAAE;EACX,CAAC;;EAED;EACA;EACA;;EAEA,MAAMM,OAAO,SAASP,OAAO,CAAC;EAC5B;IACA,WAAWD,OAAOA,GAAG;EACnB,IAAA,OAAOA,OAAO;EAChB,EAAA;IAEA,WAAWO,WAAWA,GAAG;EACvB,IAAA,OAAOA,WAAW;EACpB,EAAA;IAEA,WAAWV,IAAIA,GAAG;EAChB,IAAA,OAAOA,IAAI;EACb,EAAA;;EAEA;EACAY,EAAAA,cAAcA,GAAG;MACf,OAAO,IAAI,CAACC,SAAS,EAAE,IAAI,IAAI,CAACC,WAAW,EAAE;EAC/C,EAAA;;EAEA;EACAC,EAAAA,sBAAsBA,GAAG;MACvB,OAAO;EACL,MAAA,CAACd,cAAc,GAAG,IAAI,CAACY,SAAS,EAAE;EAClC,MAAA,CAACX,gBAAgB,GAAG,IAAI,CAACY,WAAW;OACrC;EACH,EAAA;EAEAA,EAAAA,WAAWA,GAAG;MACZ,OAAO,IAAI,CAACE,wBAAwB,CAAC,IAAI,CAACC,OAAO,CAACZ,OAAO,CAAC;EAC5D,EAAA;;EAEA;IACA,OAAOa,eAAeA,CAACC,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACC,IAAI,CAAC,YAAY;QAC3B,MAAMC,IAAI,GAAGV,OAAO,CAACW,mBAAmB,CAAC,IAAI,EAAEH,MAAM,CAAC;EAEtD,MAAA,IAAI,OAAOA,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA;EACF,MAAA;EAEA,MAAA,IAAI,OAAOE,IAAI,CAACF,MAAM,CAAC,KAAK,WAAW,EAAE;EACvC,QAAA,MAAM,IAAII,SAAS,CAAC,CAAA,iBAAA,EAAoBJ,MAAM,GAAG,CAAC;EACpD,MAAA;EAEAE,MAAAA,IAAI,CAACF,MAAM,CAAC,EAAE;EAChB,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;AAEAK,6BAAkB,CAACb,OAAO,CAAC;;;;;;;;"}
+20
View File
@@ -237,6 +237,20 @@
node.classList.remove(CLASS_NAME_ACTIVE);
}
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = ScrollSpy.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]();
});
}
}
/**
@@ -249,6 +263,12 @@
}
});
/**
* jQuery
*/
index_js.defineJQueryPlugin(ScrollSpy);
return ScrollSpy;
}));
+1 -1
View File
File diff suppressed because one or more lines are too long
+19
View File
@@ -235,6 +235,20 @@
_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') {
return;
}
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
@@ -259,6 +273,11 @@
Tab.getOrCreateInstance(element);
}
});
/**
* jQuery
*/
index_js.defineJQueryPlugin(Tab);
return Tab;
+1 -1
View File
File diff suppressed because one or more lines are too long
+19
View File
@@ -165,6 +165,19 @@
clearTimeout(this._timeout);
this._timeout = null;
}
// 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);
}
});
}
}
/**
@@ -173,6 +186,12 @@
componentFunctions_js.enableDismissTrigger(Toast);
/**
* jQuery
*/
index_js.defineJQueryPlugin(Toast);
return Toast;
}));
+1 -1
View File
File diff suppressed because one or more lines are too long
+20
View File
@@ -518,8 +518,28 @@
this.tip = null;
}
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Tooltip.getOrCreateInstance(this, config);
if (typeof config !== 'string') {
return;
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
});
}
}
/**
* jQuery
*/
index_js.defineJQueryPlugin(Tooltip);
return Tooltip;
}));
+1 -1
View File
File diff suppressed because one or more lines are too long
+29 -1
View File
@@ -81,11 +81,15 @@
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;
return object.jquery ? object[0] : object;
}
if (typeof object === 'string' && object.length > 0) {
return document.querySelector(parseSelector(object));
@@ -158,6 +162,12 @@
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') {
@@ -175,6 +185,22 @@
}
};
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.call(...args) : defaultValue;
};
@@ -229,6 +255,7 @@
return list[Math.max(0, Math.min(index, listLength - 1))];
};
exports.defineJQueryPlugin = defineJQueryPlugin;
exports.execute = execute;
exports.executeAfterTransition = executeAfterTransition;
exports.findShadowRoot = findShadowRoot;
@@ -236,6 +263,7 @@
exports.getNextActiveElement = getNextActiveElement;
exports.getTransitionDurationFromElement = getTransitionDurationFromElement;
exports.getUID = getUID;
exports.getjQuery = getjQuery;
exports.isDisabled = isDisabled;
exports.isElement = isElement;
exports.isRTL = isRTL;
+1 -1
View File
File diff suppressed because one or more lines are too long
+24
View File
@@ -8,6 +8,7 @@
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import { enableDismissTrigger } from './util/component-functions.js'
import { defineJQueryPlugin } from './util/index.js'
/**
* Constants
@@ -52,6 +53,23 @@ class Alert extends BaseComponent {
EventHandler.trigger(this._element, EVENT_CLOSED)
this.dispose()
}
// 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)
})
}
}
/**
@@ -60,4 +78,10 @@ class Alert extends BaseComponent {
enableDismissTrigger(Alert, 'close')
/**
* jQuery
*/
defineJQueryPlugin(Alert)
export default Alert
+18
View File
@@ -7,6 +7,7 @@
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import { defineJQueryPlugin } from './util/index.js'
/**
* Constants
@@ -36,6 +37,17 @@ class Button extends BaseComponent {
// 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 jQueryInterface(config) {
return this.each(function () {
const data = Button.getOrCreateInstance(this)
if (config === 'toggle') {
data[config]()
}
})
}
}
/**
@@ -51,4 +63,10 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {
data.toggle()
})
/**
* jQuery
*/
defineJQueryPlugin(Button)
export default Button
+27
View File
@@ -10,6 +10,7 @@ import EventHandler from './dom/event-handler.js'
import Manipulator from './dom/manipulator.js'
import SelectorEngine from './dom/selector-engine.js'
import {
defineJQueryPlugin,
getNextActiveElement,
isRTL,
isVisible,
@@ -402,6 +403,26 @@ class Carousel extends BaseComponent {
return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT
}
// Static
static jQueryInterface(config) {
return this.each(function () {
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]()
}
})
}
}
/**
@@ -444,4 +465,10 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
}
})
/**
* jQuery
*/
defineJQueryPlugin(Carousel)
export default Carousel
+27
View File
@@ -9,6 +9,7 @@ import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import SelectorEngine from './dom/selector-engine.js'
import {
defineJQueryPlugin,
getElement,
reflow
} from './util/index.js'
@@ -250,6 +251,26 @@ class Collapse extends BaseComponent {
element.setAttribute('aria-expanded', isOpen)
}
}
// Static
static jQueryInterface(config) {
const _config = {}
if (typeof config === 'string' && /show|hide/.test(config)) {
_config.toggle = false
}
return this.each(function () {
const data = Collapse.getOrCreateInstance(this, _config)
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`)
}
data[config]()
}
})
}
}
/**
@@ -267,4 +288,10 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
}
})
/**
* jQuery
*/
defineJQueryPlugin(Collapse)
export default Collapse
+34 -2
View File
@@ -5,6 +5,8 @@
* --------------------------------------------------------------------------
*/
import { getjQuery } from '../util/index.js'
/**
* Constants
*/
@@ -259,8 +261,38 @@ const EventHandler = {
return null
}
const evt = hydrateObj(new Event(event, { bubbles: true, cancelable: true }), args)
element.dispatchEvent(evt)
const $ = getjQuery()
const typeEvent = getTypeEvent(event)
const inNamespace = event !== typeEvent
let jQueryEvent = null
let bubbles = true
let nativeDispatch = true
let defaultPrevented = false
if (inNamespace && $) {
jQueryEvent = $.Event(event, args)
$(element).trigger(jQueryEvent)
bubbles = !jQueryEvent.isPropagationStopped()
nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()
defaultPrevented = jQueryEvent.isDefaultPrevented()
}
const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)
if (defaultPrevented) {
evt.preventDefault()
}
if (nativeDispatch) {
element.dispatchEvent(evt)
}
if (evt.defaultPrevented && jQueryEvent) {
jQueryEvent.preventDefault()
}
return evt
}
}
+24
View File
@@ -11,6 +11,7 @@ import EventHandler from './dom/event-handler.js'
import Manipulator from './dom/manipulator.js'
import SelectorEngine from './dom/selector-engine.js'
import {
defineJQueryPlugin,
execute,
getElement,
getNextActiveElement,
@@ -335,6 +336,23 @@ class Dropdown extends BaseComponent {
getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()
}
// 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.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {
return
@@ -428,4 +446,10 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
Dropdown.getOrCreateInstance(this).toggle()
})
/**
* jQuery
*/
defineJQueryPlugin(Dropdown)
export default Dropdown
+24 -1
View File
@@ -12,7 +12,7 @@ import Backdrop from './util/backdrop.js'
import { enableDismissTrigger } from './util/component-functions.js'
import FocusTrap from './util/focustrap.js'
import {
isRTL, isVisible, reflow
defineJQueryPlugin, isRTL, isVisible, reflow
} from './util/index.js'
import ScrollBarHelper from './util/scrollbar.js'
@@ -313,6 +313,23 @@ class Modal extends BaseComponent {
this._element.style.paddingLeft = ''
this._element.style.paddingRight = ''
}
// Static
static jQueryInterface(config, relatedTarget) {
return this.each(function () {
const data = Modal.getOrCreateInstance(this, config)
if (typeof config !== 'string') {
return
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`)
}
data[config](relatedTarget)
})
}
}
/**
@@ -352,4 +369,10 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
enableDismissTrigger(Modal)
/**
* jQuery
*/
defineJQueryPlugin(Modal)
export default Modal
+24
View File
@@ -12,6 +12,7 @@ import Backdrop from './util/backdrop.js'
import { enableDismissTrigger } from './util/component-functions.js'
import FocusTrap from './util/focustrap.js'
import {
defineJQueryPlugin,
isDisabled,
isVisible
} from './util/index.js'
@@ -205,6 +206,23 @@ class Offcanvas extends BaseComponent {
EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)
})
}
// 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)
})
}
}
/**
@@ -255,4 +273,10 @@ EventHandler.on(window, EVENT_RESIZE, () => {
enableDismissTrigger(Offcanvas)
/**
* jQuery
*/
defineJQueryPlugin(Offcanvas)
export default Offcanvas
+24
View File
@@ -6,6 +6,7 @@
*/
import Tooltip from './tooltip.js'
import { defineJQueryPlugin } from './util/index.js'
/**
* Constants
@@ -68,6 +69,29 @@ class Popover extends Tooltip {
_getContent() {
return this._resolvePossibleFunction(this._config.content)
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Popover.getOrCreateInstance(this, config)
if (typeof config !== 'string') {
return
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`)
}
data[config]()
})
}
}
/**
* jQuery
*/
defineJQueryPlugin(Popover)
export default Popover
+24 -1
View File
@@ -9,7 +9,7 @@ import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import SelectorEngine from './dom/selector-engine.js'
import {
getElement, isDisabled, isVisible
defineJQueryPlugin, getElement, isDisabled, isVisible
} from './util/index.js'
/**
@@ -258,6 +258,23 @@ class ScrollSpy extends BaseComponent {
node.classList.remove(CLASS_NAME_ACTIVE)
}
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = ScrollSpy.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]()
})
}
}
/**
@@ -270,4 +287,10 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
}
})
/**
* jQuery
*/
defineJQueryPlugin(ScrollSpy)
export default ScrollSpy
+23 -1
View File
@@ -8,7 +8,7 @@
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import SelectorEngine from './dom/selector-engine.js'
import { getNextActiveElement, isDisabled } from './util/index.js'
import { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'
/**
* Constants
@@ -263,6 +263,23 @@ class Tab extends BaseComponent {
_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') {
return
}
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
throw new TypeError(`No method named "${config}"`)
}
data[config]()
})
}
}
/**
@@ -289,5 +306,10 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
Tab.getOrCreateInstance(element)
}
})
/**
* jQuery
*/
defineJQueryPlugin(Tab)
export default Tab
+22 -1
View File
@@ -8,7 +8,7 @@
import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import { enableDismissTrigger } from './util/component-functions.js'
import { reflow } from './util/index.js'
import { defineJQueryPlugin, reflow } from './util/index.js'
/**
* Constants
@@ -192,6 +192,21 @@ class Toast extends BaseComponent {
clearTimeout(this._timeout)
this._timeout = null
}
// 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)
}
})
}
}
/**
@@ -200,4 +215,10 @@ class Toast extends BaseComponent {
enableDismissTrigger(Toast)
/**
* jQuery
*/
defineJQueryPlugin(Toast)
export default Toast
+25 -1
View File
@@ -10,7 +10,7 @@ import BaseComponent from './base-component.js'
import EventHandler from './dom/event-handler.js'
import Manipulator from './dom/manipulator.js'
import {
execute, findShadowRoot, getElement, getUID, isRTL, noop
defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop
} from './util/index.js'
import { DefaultAllowlist } from './util/sanitizer.js'
import TemplateFactory from './util/template-factory.js'
@@ -605,5 +605,29 @@ class Tooltip extends BaseComponent {
this.tip = null
}
}
// Static
static jQueryInterface(config) {
return this.each(function () {
const data = Tooltip.getOrCreateInstance(this, config)
if (typeof config !== 'string') {
return
}
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`)
}
data[config]()
})
}
}
/**
* jQuery
*/
defineJQueryPlugin(Tooltip)
export default Tooltip
+33 -1
View File
@@ -76,12 +76,17 @@ const isElement = 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
return object.jquery ? object[0] : object
}
if (typeof object === 'string' && object.length > 0) {
@@ -171,6 +176,14 @@ 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 => {
@@ -192,6 +205,23 @@ const onDOMContentLoaded = 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.call(...args) : defaultValue
}
@@ -254,10 +284,12 @@ const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed
}
export {
defineJQueryPlugin,
execute,
executeAfterTransition,
findShadowRoot,
getElement,
getjQuery,
getNextActiveElement,
getTransitionDurationFromElement,
getUID,
+10
View File
@@ -27,6 +27,16 @@ export const createEvent = (eventName, parameters = {}) => {
return new Event(eventName, parameters)
}
export const jQueryMock = {
elements: undefined,
fn: {},
each(fn) {
for (const element of this.elements) {
fn.call(element)
}
}
}
export const clearBodyAndDocument = () => {
const attributes = ['data-bs-padding-right', 'style']
+17 -1
View File
@@ -11,6 +11,7 @@ const { browsers } = require('./browsers.js')
const ENV = process.env
const BROWSERSTACK = Boolean(ENV.BROWSERSTACK)
const DEBUG = Boolean(ENV.DEBUG)
const JQUERY_TEST = Boolean(ENV.JQUERY)
const frameworks = [
'jasmine'
@@ -60,7 +61,7 @@ const config = {
files: [
'node_modules/hammer-simulator/index.js',
{
pattern: 'js/tests/unit/**/*.spec.js',
pattern: 'js/tests/unit/**/!(jquery).spec.js',
watched: !BROWSERSTACK
}
],
@@ -110,6 +111,21 @@ if (BROWSERSTACK) {
config.customLaunchers = browsers
config.browsers = Object.keys(browsers)
reporters.push('BrowserStack', 'kjhtml')
} else if (JQUERY_TEST) {
frameworks.push('detectBrowsers')
plugins.push(
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-detect-browsers'
)
config.detectBrowsers = detectBrowsers
config.files = [
'node_modules/jquery/dist/jquery.slim.min.js',
{
pattern: 'js/tests/unit/jquery.spec.js',
watched: false
}
]
} else {
frameworks.push('detectBrowsers')
plugins.push(
+75 -1
View File
@@ -1,6 +1,6 @@
import Alert from '../../src/alert.js'
import { getTransitionDurationFromElement } from '../../src/util/index.js'
import { clearFixture, getFixture } from '../helpers/fixture.js'
import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture.js'
describe('Alert', () => {
let fixtureEl
@@ -141,6 +141,80 @@ describe('Alert', () => {
})
})
describe('jQueryInterface', () => {
it('should handle config passed and toggle existing alert', () => {
fixtureEl.innerHTML = '<div class="alert"></div>'
const alertEl = fixtureEl.querySelector('.alert')
const alert = new Alert(alertEl)
const spy = spyOn(alert, 'close')
jQueryMock.fn.alert = Alert.jQueryInterface
jQueryMock.elements = [alertEl]
jQueryMock.fn.alert.call(jQueryMock, 'close')
expect(spy).toHaveBeenCalled()
})
it('should create new alert instance and call close', () => {
fixtureEl.innerHTML = '<div class="alert"></div>'
const alertEl = fixtureEl.querySelector('.alert')
jQueryMock.fn.alert = Alert.jQueryInterface
jQueryMock.elements = [alertEl]
expect(Alert.getInstance(alertEl)).toBeNull()
jQueryMock.fn.alert.call(jQueryMock, 'close')
expect(fixtureEl.querySelector('.alert')).toBeNull()
})
it('should just create an alert instance without calling close', () => {
fixtureEl.innerHTML = '<div class="alert"></div>'
const alertEl = fixtureEl.querySelector('.alert')
jQueryMock.fn.alert = Alert.jQueryInterface
jQueryMock.elements = [alertEl]
jQueryMock.fn.alert.call(jQueryMock)
expect(Alert.getInstance(alertEl)).not.toBeNull()
expect(fixtureEl.querySelector('.alert')).not.toBeNull()
})
it('should throw an error on undefined method', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const action = 'undefinedMethod'
jQueryMock.fn.alert = Alert.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.alert.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
it('should throw an error on protected method', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const action = '_getConfig'
jQueryMock.fn.alert = Alert.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.alert.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
})
describe('getInstance', () => {
it('should return alert instance', () => {
fixtureEl.innerHTML = '<div></div>'
+8 -1
View File
@@ -124,11 +124,18 @@ describe('Base Component', () => {
expect(DummyClass.getInstance(element)).toBeInstanceOf(DummyClass)
})
it('should accept element, either passed as a CSS selector or DOM element', () => {
it('should accept element, either passed as a CSS selector, jQuery element, or DOM element', () => {
createInstance()
expect(DummyClass.getInstance('#foo')).toEqual(instance)
expect(DummyClass.getInstance(element)).toEqual(instance)
const fakejQueryObject = {
0: element,
jquery: 'foo'
}
expect(DummyClass.getInstance(fakejQueryObject)).toEqual(instance)
})
it('should return null when there is no instance', () => {
+47 -1
View File
@@ -1,5 +1,5 @@
import Button from '../../src/button.js'
import { clearFixture, getFixture } from '../helpers/fixture.js'
import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture.js'
describe('Button', () => {
let fixtureEl
@@ -93,6 +93,52 @@ describe('Button', () => {
})
})
describe('jQueryInterface', () => {
it('should handle config passed and toggle existing button', () => {
fixtureEl.innerHTML = '<button class="btn" data-bs-toggle="button"></button>'
const btnEl = fixtureEl.querySelector('.btn')
const button = new Button(btnEl)
const spy = spyOn(button, 'toggle')
jQueryMock.fn.button = Button.jQueryInterface
jQueryMock.elements = [btnEl]
jQueryMock.fn.button.call(jQueryMock, 'toggle')
expect(spy).toHaveBeenCalled()
})
it('should create new button instance and call toggle', () => {
fixtureEl.innerHTML = '<button class="btn" data-bs-toggle="button"></button>'
const btnEl = fixtureEl.querySelector('.btn')
jQueryMock.fn.button = Button.jQueryInterface
jQueryMock.elements = [btnEl]
jQueryMock.fn.button.call(jQueryMock, 'toggle')
expect(Button.getInstance(btnEl)).not.toBeNull()
expect(btnEl).toHaveClass('active')
})
it('should just create a button instance without calling toggle', () => {
fixtureEl.innerHTML = '<button class="btn" data-bs-toggle="button"></button>'
const btnEl = fixtureEl.querySelector('.btn')
jQueryMock.fn.button = Button.jQueryInterface
jQueryMock.elements = [btnEl]
jQueryMock.fn.button.call(jQueryMock)
expect(Button.getInstance(btnEl)).not.toBeNull()
expect(btnEl).not.toHaveClass('active')
})
})
describe('getInstance', () => {
it('should return button instance', () => {
fixtureEl.innerHTML = '<div></div>'
+61 -1
View File
@@ -3,7 +3,7 @@ import EventHandler from '../../src/dom/event-handler.js'
import { isRTL, noop } from '../../src/util/index.js'
import Swipe from '../../src/util/swipe.js'
import {
clearFixture, createEvent, getFixture
clearFixture, createEvent, getFixture, jQueryMock
} from '../helpers/fixture.js'
describe('Carousel', () => {
@@ -1379,6 +1379,66 @@ describe('Carousel', () => {
})
})
describe('jQueryInterface', () => {
it('should create a carousel', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
jQueryMock.fn.carousel = Carousel.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.carousel.call(jQueryMock)
expect(Carousel.getInstance(div)).not.toBeNull()
})
it('should not re create a carousel', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const carousel = new Carousel(div)
jQueryMock.fn.carousel = Carousel.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.carousel.call(jQueryMock)
expect(Carousel.getInstance(div)).toEqual(carousel)
})
it('should call to if the config is a number', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const carousel = new Carousel(div)
const slideTo = 2
const spy = spyOn(carousel, 'to')
jQueryMock.fn.carousel = Carousel.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.carousel.call(jQueryMock, slideTo)
expect(spy).toHaveBeenCalledWith(slideTo)
})
it('should throw error on undefined method', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const action = 'undefinedMethod'
jQueryMock.fn.carousel = Carousel.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.carousel.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
})
describe('data-api', () => {
it('should init carousels with data-bs-ride="carousel" on load', () => {
fixtureEl.innerHTML = '<div data-bs-ride="carousel"></div>'
+68 -2
View File
@@ -1,6 +1,6 @@
import Collapse from '../../src/collapse.js'
import EventHandler from '../../src/dom/event-handler.js'
import { clearFixture, getFixture } from '../helpers/fixture.js'
import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture.js'
describe('Collapse', () => {
let fixtureEl
@@ -43,7 +43,30 @@ describe('Collapse', () => {
expect(collapseByElement._element).toEqual(collapseEl)
})
it('should allow object in parent config', () => {
it('should allow jquery object in parent config', () => {
fixtureEl.innerHTML = [
'<div class="my-collapse">',
' <div class="item">',
' <a data-bs-toggle="collapse" href="#">Toggle item</a>',
' <div class="collapse">Lorem ipsum</div>',
' </div>',
'</div>'
].join('')
const collapseEl = fixtureEl.querySelector('div.collapse')
const myCollapseEl = fixtureEl.querySelector('.my-collapse')
const fakejQueryObject = {
0: myCollapseEl,
jquery: 'foo'
}
const collapse = new Collapse(collapseEl, {
parent: fakejQueryObject
})
expect(collapse._config.parent).toEqual(myCollapseEl)
})
it('should allow non jquery object in parent config', () => {
fixtureEl.innerHTML = [
'<div class="my-collapse">',
' <div class="item">',
@@ -920,6 +943,49 @@ describe('Collapse', () => {
})
})
describe('jQueryInterface', () => {
it('should create a collapse', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
jQueryMock.fn.collapse = Collapse.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.collapse.call(jQueryMock)
expect(Collapse.getInstance(div)).not.toBeNull()
})
it('should not re create a collapse', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const collapse = new Collapse(div)
jQueryMock.fn.collapse = Collapse.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.collapse.call(jQueryMock)
expect(Collapse.getInstance(div)).toEqual(collapse)
})
it('should throw error on undefined method', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const action = 'undefinedMethod'
jQueryMock.fn.collapse = Collapse.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.collapse.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
})
describe('getInstance', () => {
it('should return collapse instance', () => {
fixtureEl.innerHTML = '<div></div>'
+70 -1
View File
@@ -2,7 +2,7 @@ import EventHandler from '../../src/dom/event-handler.js'
import Dropdown from '../../src/dropdown.js'
import { noop } from '../../src/util/index.js'
import {
clearFixture, createEvent, getFixture
clearFixture, createEvent, getFixture, jQueryMock
} from '../helpers/fixture.js'
describe('Dropdown', () => {
@@ -508,6 +508,32 @@ describe('Dropdown', () => {
})
})
it('should toggle a dropdown with a jquery object reference', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<div class="dropdown">',
' <button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</button>',
' <div class="dropdown-menu">',
' <a class="dropdown-item" href="#">Secondary link</a>',
' </div>',
'</div>'
].join('')
const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
const dropdown = new Dropdown(btnDropdown, {
reference: { 0: fixtureEl, jquery: 'jQuery' }
})
btnDropdown.addEventListener('shown.bs.dropdown', () => {
expect(btnDropdown).toHaveClass('show')
expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true')
resolve()
})
dropdown.toggle()
})
})
it('should toggle a dropdown with a valid virtual element reference', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
@@ -2192,6 +2218,49 @@ describe('Dropdown', () => {
})
})
describe('jQueryInterface', () => {
it('should create a dropdown', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
jQueryMock.fn.dropdown = Dropdown.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.dropdown.call(jQueryMock)
expect(Dropdown.getInstance(div)).not.toBeNull()
})
it('should not re create a dropdown', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const dropdown = new Dropdown(div)
jQueryMock.fn.dropdown = Dropdown.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.dropdown.call(jQueryMock)
expect(Dropdown.getInstance(div)).toEqual(dropdown)
})
it('should throw error on undefined method', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const action = 'undefinedMethod'
jQueryMock.fn.dropdown = Dropdown.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.dropdown.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
})
describe('getInstance', () => {
it('should return dropdown instance', () => {
fixtureEl.innerHTML = '<div></div>'
+60
View File
@@ -0,0 +1,60 @@
/* eslint-env jquery */
import Alert from '../../src/alert.js'
import Button from '../../src/button.js'
import Carousel from '../../src/carousel.js'
import Collapse from '../../src/collapse.js'
import Dropdown from '../../src/dropdown.js'
import Modal from '../../src/modal.js'
import Offcanvas from '../../src/offcanvas.js'
import Popover from '../../src/popover.js'
import ScrollSpy from '../../src/scrollspy.js'
import Tab from '../../src/tab.js'
import Toast from '../../src/toast.js'
import Tooltip from '../../src/tooltip.js'
import { clearFixture, getFixture } from '../helpers/fixture.js'
describe('jQuery', () => {
let fixtureEl
beforeAll(() => {
fixtureEl = getFixture()
})
afterEach(() => {
clearFixture()
})
it('should add all plugins in jQuery', () => {
expect(Alert.jQueryInterface).toEqual(jQuery.fn.alert)
expect(Button.jQueryInterface).toEqual(jQuery.fn.button)
expect(Carousel.jQueryInterface).toEqual(jQuery.fn.carousel)
expect(Collapse.jQueryInterface).toEqual(jQuery.fn.collapse)
expect(Dropdown.jQueryInterface).toEqual(jQuery.fn.dropdown)
expect(Modal.jQueryInterface).toEqual(jQuery.fn.modal)
expect(Offcanvas.jQueryInterface).toEqual(jQuery.fn.offcanvas)
expect(Popover.jQueryInterface).toEqual(jQuery.fn.popover)
expect(ScrollSpy.jQueryInterface).toEqual(jQuery.fn.scrollspy)
expect(Tab.jQueryInterface).toEqual(jQuery.fn.tab)
expect(Toast.jQueryInterface).toEqual(jQuery.fn.toast)
expect(Tooltip.jQueryInterface).toEqual(jQuery.fn.tooltip)
})
it('should use jQuery event system', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<div class="alert">',
' <button type="button" data-bs-dismiss="alert">x</button>',
'</div>'
].join('')
$(fixtureEl).find('.alert')
.one('closed.bs.alert', () => {
expect($(fixtureEl).find('.alert')).toHaveSize(0)
resolve()
})
$(fixtureEl).find('button').trigger('click')
})
})
})
+91 -1
View File
@@ -2,7 +2,7 @@ import EventHandler from '../../src/dom/event-handler.js'
import Modal from '../../src/modal.js'
import ScrollBarHelper from '../../src/util/scrollbar.js'
import {
clearBodyAndDocument, clearFixture, createEvent, getFixture
clearBodyAndDocument, clearFixture, createEvent, getFixture, jQueryMock
} from '../helpers/fixture.js'
describe('Modal', () => {
@@ -1162,6 +1162,96 @@ describe('Modal', () => {
})
})
})
describe('jQueryInterface', () => {
it('should create a modal', () => {
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
const div = fixtureEl.querySelector('div')
jQueryMock.fn.modal = Modal.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.modal.call(jQueryMock)
expect(Modal.getInstance(div)).not.toBeNull()
})
it('should create a modal with given config', () => {
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
const div = fixtureEl.querySelector('div')
jQueryMock.fn.modal = Modal.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.modal.call(jQueryMock, { keyboard: false })
const spy = spyOn(Modal.prototype, 'constructor')
expect(spy).not.toHaveBeenCalledWith(div, { keyboard: false })
const modal = Modal.getInstance(div)
expect(modal).not.toBeNull()
expect(modal._config.keyboard).toBeFalse()
})
it('should not re create a modal', () => {
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
const div = fixtureEl.querySelector('div')
const modal = new Modal(div)
jQueryMock.fn.modal = Modal.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.modal.call(jQueryMock)
expect(Modal.getInstance(div)).toEqual(modal)
})
it('should throw error on undefined method', () => {
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
const div = fixtureEl.querySelector('div')
const action = 'undefinedMethod'
jQueryMock.fn.modal = Modal.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.modal.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
it('should call show method', () => {
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
const div = fixtureEl.querySelector('div')
const modal = new Modal(div)
jQueryMock.fn.modal = Modal.jQueryInterface
jQueryMock.elements = [div]
const spy = spyOn(modal, 'show')
jQueryMock.fn.modal.call(jQueryMock, 'show')
expect(spy).toHaveBeenCalled()
})
it('should not call show method', () => {
fixtureEl.innerHTML = '<div class="modal" data-bs-show="false"><div class="modal-dialog"></div></div>'
const div = fixtureEl.querySelector('div')
jQueryMock.fn.modal = Modal.jQueryInterface
jQueryMock.elements = [div]
const spy = spyOn(Modal.prototype, 'show')
jQueryMock.fn.modal.call(jQueryMock)
expect(spy).not.toHaveBeenCalled()
})
})
describe('getInstance', () => {
it('should return modal instance', () => {
+101 -1
View File
@@ -3,7 +3,7 @@ import Offcanvas from '../../src/offcanvas.js'
import { isVisible } from '../../src/util/index.js'
import ScrollBarHelper from '../../src/util/scrollbar.js'
import {
clearBodyAndDocument, clearFixture, createEvent, getFixture
clearBodyAndDocument, clearFixture, createEvent, getFixture, jQueryMock
} from '../helpers/fixture.js'
describe('Offcanvas', () => {
@@ -738,6 +738,106 @@ describe('Offcanvas', () => {
})
})
describe('jQueryInterface', () => {
it('should create an offcanvas', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
jQueryMock.fn.offcanvas = Offcanvas.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.offcanvas.call(jQueryMock)
expect(Offcanvas.getInstance(div)).not.toBeNull()
})
it('should not re create an offcanvas', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const offCanvas = new Offcanvas(div)
jQueryMock.fn.offcanvas = Offcanvas.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.offcanvas.call(jQueryMock)
expect(Offcanvas.getInstance(div)).toEqual(offCanvas)
})
it('should throw error on undefined method', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const action = 'undefinedMethod'
jQueryMock.fn.offcanvas = Offcanvas.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.offcanvas.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
it('should throw error on protected method', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const action = '_getConfig'
jQueryMock.fn.offcanvas = Offcanvas.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.offcanvas.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
it('should throw error if method "constructor" is being called', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const action = 'constructor'
jQueryMock.fn.offcanvas = Offcanvas.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.offcanvas.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
it('should call offcanvas method', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const spy = spyOn(Offcanvas.prototype, 'show')
jQueryMock.fn.offcanvas = Offcanvas.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.offcanvas.call(jQueryMock, 'show')
expect(spy).toHaveBeenCalled()
})
it('should create a offcanvas with given config', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
jQueryMock.fn.offcanvas = Offcanvas.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.offcanvas.call(jQueryMock, { scroll: true })
const offcanvas = Offcanvas.getInstance(div)
expect(offcanvas).not.toBeNull()
expect(offcanvas._config.scroll).toBeTrue()
})
})
describe('getInstance', () => {
it('should return offcanvas instance', () => {
fixtureEl.innerHTML = '<div></div>'
+75 -1
View File
@@ -1,7 +1,7 @@
import EventHandler from '../../src/dom/event-handler.js'
import Popover from '../../src/popover.js'
import {
clearFixture, getFixture, createEvent
clearFixture, getFixture, jQueryMock, createEvent
} from '../helpers/fixture.js'
describe('Popover', () => {
@@ -361,6 +361,80 @@ describe('Popover', () => {
})
})
describe('jQueryInterface', () => {
it('should create a popover', () => {
fixtureEl.innerHTML = '<a href="#" title="Popover" data-bs-content="https://x.com/getbootstrap">BS X</a>'
const popoverEl = fixtureEl.querySelector('a')
jQueryMock.fn.popover = Popover.jQueryInterface
jQueryMock.elements = [popoverEl]
jQueryMock.fn.popover.call(jQueryMock)
expect(Popover.getInstance(popoverEl)).not.toBeNull()
})
it('should create a popover with a config object', () => {
fixtureEl.innerHTML = '<a href="#" title="Popover">BS X</a>'
const popoverEl = fixtureEl.querySelector('a')
jQueryMock.fn.popover = Popover.jQueryInterface
jQueryMock.elements = [popoverEl]
jQueryMock.fn.popover.call(jQueryMock, {
content: 'Popover content'
})
expect(Popover.getInstance(popoverEl)).not.toBeNull()
})
it('should not re create a popover', () => {
fixtureEl.innerHTML = '<a href="#" title="Popover" data-bs-content="https://x.com/getbootstrap">BS X</a>'
const popoverEl = fixtureEl.querySelector('a')
const popover = new Popover(popoverEl)
jQueryMock.fn.popover = Popover.jQueryInterface
jQueryMock.elements = [popoverEl]
jQueryMock.fn.popover.call(jQueryMock)
expect(Popover.getInstance(popoverEl)).toEqual(popover)
})
it('should throw error on undefined method', () => {
fixtureEl.innerHTML = '<a href="#" title="Popover" data-bs-content="https://x.com/getbootstrap">BS X</a>'
const popoverEl = fixtureEl.querySelector('a')
const action = 'undefinedMethod'
jQueryMock.fn.popover = Popover.jQueryInterface
jQueryMock.elements = [popoverEl]
expect(() => {
jQueryMock.fn.popover.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
it('should should call show method', () => {
fixtureEl.innerHTML = '<a href="#" title="Popover" data-bs-content="https://x.com/getbootstrap">BS X</a>'
const popoverEl = fixtureEl.querySelector('a')
const popover = new Popover(popoverEl)
jQueryMock.fn.popover = Popover.jQueryInterface
jQueryMock.elements = [popoverEl]
const spy = spyOn(popover, 'show')
jQueryMock.fn.popover.call(jQueryMock, 'show')
expect(spy).toHaveBeenCalled()
})
})
describe('getInstance', () => {
it('should return popover instance', () => {
fixtureEl.innerHTML = '<a href="#" title="Popover" data-bs-content="https://x.com/getbootstrap">BS X</a>'
+106 -1
View File
@@ -1,7 +1,7 @@
import EventHandler from '../../src/dom/event-handler.js'
import ScrollSpy from '../../src/scrollspy.js'
import {
clearFixture, createEvent, getFixture
clearFixture, createEvent, getFixture, jQueryMock
} from '../helpers/fixture.js'
describe('ScrollSpy', () => {
@@ -648,6 +648,111 @@ describe('ScrollSpy', () => {
})
})
describe('jQueryInterface', () => {
it('should create a scrollspy', () => {
fixtureEl.innerHTML = getDummyFixture()
const div = fixtureEl.querySelector('.content')
jQueryMock.fn.scrollspy = ScrollSpy.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.scrollspy.call(jQueryMock, { target: '#navBar' })
expect(ScrollSpy.getInstance(div)).not.toBeNull()
})
it('should create a scrollspy with given config', () => {
fixtureEl.innerHTML = getDummyFixture()
const div = fixtureEl.querySelector('.content')
jQueryMock.fn.scrollspy = ScrollSpy.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.scrollspy.call(jQueryMock, { rootMargin: '100px' })
const spy = spyOn(ScrollSpy.prototype, 'constructor')
expect(spy).not.toHaveBeenCalledWith(div, { rootMargin: '100px' })
const scrollspy = ScrollSpy.getInstance(div)
expect(scrollspy).not.toBeNull()
expect(scrollspy._config.rootMargin).toEqual('100px')
})
it('should not re create a scrollspy', () => {
fixtureEl.innerHTML = getDummyFixture()
const div = fixtureEl.querySelector('.content')
const scrollSpy = new ScrollSpy(div)
jQueryMock.fn.scrollspy = ScrollSpy.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.scrollspy.call(jQueryMock)
expect(ScrollSpy.getInstance(div)).toEqual(scrollSpy)
})
it('should call a scrollspy method', () => {
fixtureEl.innerHTML = getDummyFixture()
const div = fixtureEl.querySelector('.content')
const scrollSpy = new ScrollSpy(div)
const spy = spyOn(scrollSpy, 'refresh')
jQueryMock.fn.scrollspy = ScrollSpy.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.scrollspy.call(jQueryMock, 'refresh')
expect(ScrollSpy.getInstance(div)).toEqual(scrollSpy)
expect(spy).toHaveBeenCalled()
})
it('should throw error on undefined method', () => {
fixtureEl.innerHTML = getDummyFixture()
const div = fixtureEl.querySelector('.content')
const action = 'undefinedMethod'
jQueryMock.fn.scrollspy = ScrollSpy.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.scrollspy.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
it('should throw error on protected method', () => {
fixtureEl.innerHTML = getDummyFixture()
const div = fixtureEl.querySelector('.content')
const action = '_getConfig'
jQueryMock.fn.scrollspy = ScrollSpy.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.scrollspy.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
it('should throw error if method "constructor" is being called', () => {
fixtureEl.innerHTML = getDummyFixture()
const div = fixtureEl.querySelector('.content')
const action = 'constructor'
jQueryMock.fn.scrollspy = ScrollSpy.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.scrollspy.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
})
describe('getInstance', () => {
it('should return scrollspy instance', () => {
fixtureEl.innerHTML = getDummyFixture()
+61 -1
View File
@@ -1,6 +1,6 @@
import Tab from '../../src/tab.js'
import {
clearFixture, createEvent, getFixture
clearFixture, createEvent, getFixture, jQueryMock
} from '../helpers/fixture.js'
describe('Tab', () => {
@@ -827,6 +827,66 @@ describe('Tab', () => {
})
})
describe('jQueryInterface', () => {
it('should create a tab', () => {
fixtureEl.innerHTML = '<div class="nav"><div class="nav-link"></div></div>'
const div = fixtureEl.querySelector('.nav > div')
jQueryMock.fn.tab = Tab.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.tab.call(jQueryMock)
expect(Tab.getInstance(div)).not.toBeNull()
})
it('should not re create a tab', () => {
fixtureEl.innerHTML = '<div class="nav"><div class="nav-link"></div></div>'
const div = fixtureEl.querySelector('.nav > div')
const tab = new Tab(div)
jQueryMock.fn.tab = Tab.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.tab.call(jQueryMock)
expect(Tab.getInstance(div)).toEqual(tab)
})
it('should call a tab method', () => {
fixtureEl.innerHTML = '<div class="nav"><div class="nav-link"></div></div>'
const div = fixtureEl.querySelector('.nav > div')
const tab = new Tab(div)
const spy = spyOn(tab, 'show')
jQueryMock.fn.tab = Tab.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.tab.call(jQueryMock, 'show')
expect(Tab.getInstance(div)).toEqual(tab)
expect(spy).toHaveBeenCalled()
})
it('should throw error on undefined method', () => {
fixtureEl.innerHTML = '<div class="nav"><div class="nav-link"></div></div>'
const div = fixtureEl.querySelector('.nav > div')
const action = 'undefinedMethod'
jQueryMock.fn.tab = Tab.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.tab.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
})
describe('getInstance', () => {
it('should return null if there is no instance', () => {
expect(Tab.getInstance(fixtureEl)).toBeNull()
+61 -1
View File
@@ -1,6 +1,6 @@
import Toast from '../../src/toast.js'
import {
clearFixture, createEvent, getFixture
clearFixture, createEvent, getFixture, jQueryMock
} from '../helpers/fixture.js'
describe('Toast', () => {
@@ -536,6 +536,66 @@ describe('Toast', () => {
})
})
describe('jQueryInterface', () => {
it('should create a toast', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
jQueryMock.fn.toast = Toast.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.toast.call(jQueryMock)
expect(Toast.getInstance(div)).not.toBeNull()
})
it('should not re create a toast', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const toast = new Toast(div)
jQueryMock.fn.toast = Toast.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.toast.call(jQueryMock)
expect(Toast.getInstance(div)).toEqual(toast)
})
it('should call a toast method', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const toast = new Toast(div)
const spy = spyOn(toast, 'show')
jQueryMock.fn.toast = Toast.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.toast.call(jQueryMock, 'show')
expect(Toast.getInstance(div)).toEqual(toast)
expect(spy).toHaveBeenCalled()
})
it('should throw error on undefined method', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const action = 'undefinedMethod'
jQueryMock.fn.toast = Toast.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.toast.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
})
describe('getInstance', () => {
it('should return a toast instance', () => {
fixtureEl.innerHTML = '<div></div>'
+101 -1
View File
@@ -2,7 +2,7 @@ import EventHandler from '../../src/dom/event-handler.js'
import Tooltip from '../../src/tooltip.js'
import { noop } from '../../src/util/index.js'
import {
clearFixture, createEvent, getFixture
clearFixture, createEvent, getFixture, jQueryMock
} from '../helpers/fixture.js'
describe('Tooltip', () => {
@@ -582,6 +582,27 @@ describe('Tooltip', () => {
})
})
it('should show a tooltip with a jquery element container', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>'
const tooltipEl = fixtureEl.querySelector('a')
const tooltip = new Tooltip(tooltipEl, {
container: {
0: fixtureEl,
jquery: 'jQuery'
}
})
tooltipEl.addEventListener('shown.bs.tooltip', () => {
expect(fixtureEl.querySelector('.tooltip')).not.toBeNull()
resolve()
})
tooltip.show()
})
})
it('should show a tooltip with a selector in container', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"></a>'
@@ -1222,6 +1243,25 @@ describe('Tooltip', () => {
expect().nothing()
})
it('should add the content as a child of the element for jQuery elements', () => {
fixtureEl.innerHTML = [
'<a href="#" rel="tooltip" title="Another tooltip">',
' <div id="childContent"></div>',
'</a>'
].join('')
const tooltipEl = fixtureEl.querySelector('a')
const childContent = fixtureEl.querySelector('div')
const tooltip = new Tooltip(tooltipEl, {
html: true
})
tooltip.setContent({ '.tooltip': { 0: childContent, jquery: 'jQuery' } })
tooltip.show()
expect(childContent.parentNode).toEqual(tooltip._getTipElement())
})
it('should add the child text content in the element', () => {
fixtureEl.innerHTML = [
'<a href="#" rel="tooltip" title="Another tooltip">',
@@ -1482,4 +1522,64 @@ describe('Tooltip', () => {
expect(tooltip2._getTitle()).toEqual('nothing')
})
})
describe('jQueryInterface', () => {
it('should create a tooltip', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
jQueryMock.fn.tooltip = Tooltip.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.tooltip.call(jQueryMock)
expect(Tooltip.getInstance(div)).not.toBeNull()
})
it('should not re create a tooltip', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const tooltip = new Tooltip(div)
jQueryMock.fn.tooltip = Tooltip.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.tooltip.call(jQueryMock)
expect(Tooltip.getInstance(div)).toEqual(tooltip)
})
it('should call a tooltip method', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const tooltip = new Tooltip(div)
const spy = spyOn(tooltip, 'show')
jQueryMock.fn.tooltip = Tooltip.jQueryInterface
jQueryMock.elements = [div]
jQueryMock.fn.tooltip.call(jQueryMock, 'show')
expect(Tooltip.getInstance(div)).toEqual(tooltip)
expect(spy).toHaveBeenCalled()
})
it('should throw error on undefined method', () => {
fixtureEl.innerHTML = '<div></div>'
const div = fixtureEl.querySelector('div')
const action = 'undefinedMethod'
jQueryMock.fn.tooltip = Tooltip.jQueryInterface
jQueryMock.elements = [div]
expect(() => {
jQueryMock.fn.tooltip.call(jQueryMock, action)
}).toThrowError(TypeError, `No method named "${action}"`)
})
})
})
+78
View File
@@ -72,6 +72,18 @@ describe('Util', () => {
expect(Util.isElement({})).toBeFalse()
expect(Util.isElement(fixtureEl.querySelectorAll('.test'))).toBeFalse()
})
it('should detect jQuery element', () => {
fixtureEl.innerHTML = '<div></div>'
const el = fixtureEl.querySelector('div')
const fakejQuery = {
0: el,
jquery: 'foo'
}
expect(Util.isElement(fakejQuery)).toBeTrue()
})
})
describe('getElement', () => {
@@ -91,6 +103,13 @@ describe('Util', () => {
expect(Util.getElement()).toBeNull()
expect(Util.getElement(null)).toBeNull()
expect(Util.getElement(fixtureEl.querySelectorAll('.test'))).toBeNull()
const fakejQueryObject = {
0: el,
jquery: 'foo'
}
expect(Util.getElement(fakejQueryObject)).toEqual(el)
})
})
@@ -406,6 +425,39 @@ describe('Util', () => {
})
})
describe('getjQuery', () => {
const fakejQuery = { trigger() {} }
beforeEach(() => {
Object.defineProperty(window, 'jQuery', {
value: fakejQuery,
writable: true
})
})
afterEach(() => {
window.jQuery = undefined
})
it('should return jQuery object when present', () => {
expect(Util.getjQuery()).toEqual(fakejQuery)
})
it('should not return jQuery object when present if data-bs-no-jquery', () => {
document.body.setAttribute('data-bs-no-jquery', '')
expect(window.jQuery).toEqual(fakejQuery)
expect(Util.getjQuery()).toBeNull()
document.body.removeAttribute('data-bs-no-jquery')
})
it('should not return jQuery if not present', () => {
window.jQuery = undefined
expect(Util.getjQuery()).toBeNull()
})
})
describe('onDOMContentLoaded', () => {
it('should execute callbacks when DOMContentLoaded is fired and should not add more than one listener', () => {
const spy = jasmine.createSpy()
@@ -434,6 +486,32 @@ describe('Util', () => {
})
})
describe('defineJQueryPlugin', () => {
const fakejQuery = { fn: {} }
beforeEach(() => {
Object.defineProperty(window, 'jQuery', {
value: fakejQuery,
writable: true
})
})
afterEach(() => {
window.jQuery = undefined
})
it('should define a plugin on the jQuery instance', () => {
const pluginMock = Util.noop
pluginMock.NAME = 'test'
pluginMock.jQueryInterface = Util.noop
Util.defineJQueryPlugin(pluginMock)
expect(fakejQuery.fn.test).toEqual(pluginMock.jQueryInterface)
expect(fakejQuery.fn.test.Constructor).toEqual(pluginMock)
expect(fakejQuery.fn.test.noConflict).toEqual(jasmine.any(Function))
})
})
describe('execute', () => {
it('should execute if arg is function', () => {
const spy = jasmine.createSpy('spy')
+790 -1624
View File
File diff suppressed because it is too large Load Diff
+15 -15
View File
@@ -42,7 +42,7 @@
"start": "npm-run-all --parallel watch docs-serve",
"bundlewatch": "bundlewatch --config .bundlewatch.config.json",
"css": "npm-run-all css-compile css-prefix css-rtl css-minify",
"css-compile": "sass --style expanded --source-map --embed-sources --no-error-css scss/bootstrap.scss:dist/css/bootstrap.css scss/bootstrap-grid.scss:dist/css/bootstrap-grid.css scss/bootstrap-reboot.scss:dist/css/bootstrap-reboot.css scss/bootstrap-utilities.scss:dist/css/bootstrap-utilities.css",
"css-compile": "sass --style expanded --source-map --embed-sources --no-error-css scss/:dist/css/",
"css-rtl": "cross-env NODE_ENV=RTL postcss --config build/postcss.config.mjs --dir \"dist/css\" --ext \".rtl.css\" \"dist/css/*.css\" \"!dist/css/*.min.css\" \"!dist/css/*.rtl.css\"",
"css-lint": "npm-run-all --aggregate-output --continue-on-error --parallel css-lint-*",
"css-lint-stylelint": "stylelint \"**/*.{css,scss}\" --cache --cache-location .cache/.stylelintcache",
@@ -66,14 +66,14 @@
"js-minify-standalone": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.js.map,includeSources,url=bootstrap.min.js.map\" --output dist/js/bootstrap.min.js dist/js/bootstrap.js",
"js-minify-standalone-esm": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.esm.js.map,includeSources,url=bootstrap.esm.min.js.map\" --output dist/js/bootstrap.esm.min.js dist/js/bootstrap.esm.js",
"js-minify-bundle": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.bundle.js.map,includeSources,url=bootstrap.bundle.min.js.map\" --output dist/js/bootstrap.bundle.min.js dist/js/bootstrap.bundle.js",
"js-test": "npm-run-all --aggregate-output --parallel js-test-karma js-test-integration-*",
"js-test": "npm-run-all --aggregate-output --parallel js-test-karma js-test-jquery js-test-integration-*",
"js-debug": "cross-env DEBUG=true npm run js-test-karma",
"js-test-karma": "karma start js/tests/karma.conf.js",
"js-test-integration-bundle": "rollup --config js/tests/integration/rollup.bundle.js",
"js-test-integration-modularity": "rollup --config js/tests/integration/rollup.bundle-modularity.js",
"js-test-cloud": "cross-env BROWSERSTACK=true npm run js-test-karma",
"lint": "npm-run-all --aggregate-output --continue-on-error --parallel js-lint css-lint lockfile-lint lint-mdx",
"lint-mdx": "markdownlint \"site/src/content/**/*.mdx\"",
"js-test-jquery": "cross-env JQUERY=true npm run js-test-karma",
"lint": "npm-run-all --aggregate-output --continue-on-error --parallel js-lint css-lint lockfile-lint",
"docs": "npm-run-all docs-build docs-lint",
"docs-build": "npm run astro-build",
"docs-compile": "npm run docs-build",
@@ -84,7 +84,7 @@
"docs-serve": "npm run astro-dev",
"docs-serve-only": "npx sirv-cli _site --port 9001",
"lockfile-lint": "lockfile-lint --allowed-hosts npm --allowed-schemes https: --empty-hostname false --type npm --path package-lock.json",
"update-deps": "ncu -u -x @docsearch/js,eslint,eslint-config-xo,eslint-plugin-unicorn,karma-browserstack-launcher,karma-rollup-preprocessor,sass",
"update-deps": "ncu -u -x eslint,eslint-config-xo,eslint-plugin-unicorn,karma-browserstack-launcher,karma-rollup-preprocessor,sass",
"release": "npm-run-all dist release-sri docs-build release-zip*",
"release-sri": "node build/generate-sri.mjs",
"release-version": "node build/change-version.mjs",
@@ -110,11 +110,11 @@
"devDependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/markdown-remark": "^6.3.6",
"@astrojs/mdx": "^4.3.5",
"@astrojs/mdx": "^4.3.4",
"@astrojs/prism": "^3.3.0",
"@astrojs/sitemap": "^3.6.0",
"@astrojs/sitemap": "^3.5.1",
"@babel/cli": "^7.28.3",
"@babel/core": "^7.28.4",
"@babel/core": "^7.28.3",
"@babel/preset-env": "^7.28.3",
"@docsearch/js": "^3.9.0",
"@popperjs/core": "^2.11.8",
@@ -126,7 +126,7 @@
"@types/js-yaml": "^4.0.9",
"@types/mime": "^4.0.0",
"@types/prismjs": "^1.26.5",
"astro": "^5.13.9",
"astro": "^5.13.5",
"astro-auto-import": "^0.4.4",
"autoprefixer": "^10.4.21",
"bundlewatch": "^0.4.1",
@@ -147,6 +147,7 @@
"image-size": "^2.0.2",
"ip": "^2.0.1",
"jasmine": "^5.10.0",
"jquery": "^3.7.1",
"js-yaml": "^4.1.0",
"karma": "^6.4.4",
"karma-browserstack-launcher": "1.4.0",
@@ -158,8 +159,7 @@
"karma-jasmine-html-reporter": "^2.1.0",
"karma-rollup-preprocessor": "7.0.7",
"lockfile-lint": "^4.14.1",
"markdownlint-cli": "^0.45.0",
"mime": "^4.1.0",
"mime": "^4.0.7",
"nodemon": "^3.1.10",
"npm-run-all2": "^8.0.4",
"postcss": "^8.5.6",
@@ -169,18 +169,18 @@
"rehype-autolink-headings": "^7.1.0",
"remark": "^15.0.1",
"remark-html": "^16.0.1",
"rollup": "^4.52.0",
"rollup": "^4.50.0",
"rollup-plugin-istanbul": "^5.0.0",
"rtlcss": "^4.3.0",
"sass": "^1.90.0",
"sass": "1.78.0",
"sass-true": "^9.0.0",
"shelljs": "^0.10.0",
"stylelint": "^16.24.0",
"stylelint": "^16.23.1",
"stylelint-config-twbs-bootstrap": "^16.1.0",
"terser": "^5.44.0",
"unist-util-visit": "^5.0.0",
"vnu-jar": "24.10.17",
"zod": "^4.1.9"
"zod": "^4.1.5"
},
"files": [
"dist/{css,js}/*.{css,js,map}",
+151 -185
View File
@@ -1,187 +1,153 @@
@use "config" as *;
@use "variables" as *;
@use "functions" as *;
@use "vendor/rfs" as *;
@use "mixins/border-radius" as *;
@use "mixins/transition" as *;
@use "mixins/box-shadow" as *;
@use "mixins/color-mode" as *;
//
// Base styles
//
// scss-docs-start accordion-variables
$accordion-padding-y: 1rem !default;
$accordion-padding-x: 1.25rem !default;
$accordion-color: var(--#{$prefix}body-color) !default;
$accordion-bg: var(--#{$prefix}body-bg) !default;
$accordion-border-width: var(--#{$prefix}border-width) !default;
$accordion-border-color: var(--#{$prefix}border-color) !default;
$accordion-border-radius: var(--#{$prefix}border-radius-lg) !default;
$accordion-inner-border-radius: calc(#{$accordion-border-radius} - #{$accordion-border-width}) !default;
$accordion-body-padding-y: $accordion-padding-y !default;
$accordion-body-padding-x: $accordion-padding-x !default;
$accordion-button-padding-y: $accordion-padding-y !default;
$accordion-button-padding-x: $accordion-padding-x !default;
$accordion-button-color: var(--#{$prefix}fg-2) !default;
$accordion-button-bg: var(--#{$prefix}accordion-bg) !default;
$accordion-transition: $btn-transition, border-radius .15s ease !default;
$accordion-button-active-bg: var(--#{$prefix}bg-2) !default;
$accordion-button-active-color: var(--#{$prefix}fg) !default;
$accordion-button-focus-box-shadow: $btn-focus-box-shadow !default;
$accordion-icon-width: 1.25rem !default;
$accordion-icon-transition: transform .2s ease-in-out !default;
$accordion-icon-transform: rotate(-180deg) !default;
$accordion-button-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='#000' stroke-linecap='round' stroke-linejoin='round'><path d='m2 5 6 6 6-6'/></svg>") !default;
// scss-docs-end accordion-variables
@layer componenents {
.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-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: var(--#{$prefix}accordion-btn-padding-y) var(--#{$prefix}accordion-btn-padding-x);
@include font-size($font-size-base);
color: var(--#{$prefix}accordion-btn-color);
text-align: left; // Reset button style
background-color: var(--#{$prefix}accordion-btn-bg);
border: 0;
@include border-radius(0);
overflow-anchor: none;
@include transition(var(--#{$prefix}accordion-transition));
&:not(.collapsed) {
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);
&::after {
background-image: var(--#{$prefix}accordion-btn-active-icon);
transform: var(--#{$prefix}accordion-btn-icon-transform);
}
}
// Accordion icon
&::after {
flex-shrink: 0;
width: var(--#{$prefix}accordion-btn-icon-width);
height: var(--#{$prefix}accordion-btn-icon-width);
margin-left: auto;
content: "";
background-color: var(--#{$prefix}accordion-btn-color);
mask: var(--#{$prefix}accordion-btn-icon) no-repeat center 100%;
@include transition(var(--#{$prefix}accordion-btn-icon-transition));
}
&:hover {
z-index: 2;
}
&:focus {
z-index: 3;
outline: 0;
box-shadow: var(--#{$prefix}accordion-btn-focus-box-shadow);
}
}
.accordion-header {
margin-bottom: 0;
}
.accordion-item {
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(var(--#{$prefix}accordion-border-radius));
> .accordion-header .accordion-button {
@include border-top-radius(var(--#{$prefix}accordion-inner-border-radius));
}
}
&:not(:first-of-type) {
border-top: 0;
}
// Only set a border-radius on the last item if the accordion is collapsed
&:last-of-type {
@include border-bottom-radius(var(--#{$prefix}accordion-border-radius));
> .accordion-header .accordion-button {
&.collapsed {
@include border-bottom-radius(var(--#{$prefix}accordion-inner-border-radius));
}
}
> .accordion-collapse {
@include border-bottom-radius(var(--#{$prefix}accordion-border-radius));
}
}
}
.accordion-body {
padding: var(--#{$prefix}accordion-body-padding-y) var(--#{$prefix}accordion-body-padding-x);
}
// Flush accordion items
//
// Remove borders and border-radius to keep accordion items edge-to-edge.
.accordion-flush {
> .accordion-item {
border-right: 0;
border-left: 0;
@include border-radius(0);
&:first-child { border-top: 0; }
&:last-child { border-bottom: 0; }
// stylelint-disable selector-max-class
> .accordion-collapse,
> .accordion-header .accordion-button,
> .accordion-header .accordion-button.collapsed {
@include border-radius(0);
}
// stylelint-enable selector-max-class
}
}
// @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)};
// }
// }
// }
.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: var(--#{$prefix}accordion-btn-padding-y) var(--#{$prefix}accordion-btn-padding-x);
@include font-size($font-size-base);
color: var(--#{$prefix}accordion-btn-color);
text-align: left; // Reset button style
background-color: var(--#{$prefix}accordion-btn-bg);
border: 0;
@include border-radius(0);
overflow-anchor: none;
@include transition(var(--#{$prefix}accordion-transition));
&:not(.collapsed) {
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: var(--#{$prefix}accordion-btn-active-icon);
transform: var(--#{$prefix}accordion-btn-icon-transform);
}
}
// Accordion icon
&::after {
flex-shrink: 0;
width: var(--#{$prefix}accordion-btn-icon-width);
height: var(--#{$prefix}accordion-btn-icon-width);
margin-left: auto;
content: "";
background-image: var(--#{$prefix}accordion-btn-icon);
background-repeat: no-repeat;
background-size: var(--#{$prefix}accordion-btn-icon-width);
@include transition(var(--#{$prefix}accordion-btn-icon-transition));
}
&:hover {
z-index: 2;
}
&:focus {
z-index: 3;
outline: 0;
box-shadow: var(--#{$prefix}accordion-btn-focus-box-shadow);
}
}
.accordion-header {
margin-bottom: 0;
}
.accordion-item {
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(var(--#{$prefix}accordion-border-radius));
> .accordion-header .accordion-button {
@include border-top-radius(var(--#{$prefix}accordion-inner-border-radius));
}
}
&:not(:first-of-type) {
border-top: 0;
}
// Only set a border-radius on the last item if the accordion is collapsed
&:last-of-type {
@include border-bottom-radius(var(--#{$prefix}accordion-border-radius));
> .accordion-header .accordion-button {
&.collapsed {
@include border-bottom-radius(var(--#{$prefix}accordion-inner-border-radius));
}
}
> .accordion-collapse {
@include border-bottom-radius(var(--#{$prefix}accordion-border-radius));
}
}
}
.accordion-body {
padding: var(--#{$prefix}accordion-body-padding-y) var(--#{$prefix}accordion-body-padding-x);
}
// Flush accordion items
//
// Remove borders and border-radius to keep accordion items edge-to-edge.
.accordion-flush {
> .accordion-item {
border-right: 0;
border-left: 0;
@include border-radius(0);
&:first-child { border-top: 0; }
&:last-child { border-bottom: 0; }
// stylelint-disable selector-max-class
> .accordion-collapse,
> .accordion-header .accordion-button,
> .accordion-header .accordion-button.collapsed {
@include border-radius(0);
}
// stylelint-enable selector-max-class
}
}
@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)};
}
}
}
+65 -78
View File
@@ -1,81 +1,68 @@
@use "sass:map";
@use "config" as *;
@use "variables" as *;
@use "mixins/border-radius" as *;
//
// Base styles
//
// scss-docs-start alert-variables
$alert-padding-y: $spacer !default;
$alert-padding-x: $spacer !default;
$alert-margin-bottom: 1rem !default;
$alert-border-radius: var(--#{$prefix}border-radius) !default;
$alert-link-font-weight: $font-weight-bold !default;
$alert-border-width: var(--#{$prefix}border-width) !default;
$alert-dismissible-padding-r: $alert-padding-x * 3 !default; // 3x covers width of x plus default padding on either side
// scss-docs-end alert-variables
.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
@layer components {
.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: 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
.alert-heading {
// Specified to prevent conflicts of changing $headings-color
color: inherit;
}
// Provide class for links that match alerts
.alert-link {
font-weight: $alert-link-font-weight;
color: var(--#{$prefix}alert-link-color);
}
// Dismissible alerts
//
// Expand the right padding and account for the close button's positioning.
.alert-dismissible {
padding-right: $alert-dismissible-padding-r;
// Adjust close link position
.btn-close {
position: absolute;
top: 0;
right: 0;
z-index: $stretched-link-z-index + 1;
padding: $alert-padding-y * 1.25 $alert-padding-x;
}
}
// scss-docs-start alert-modifiers
// Generate contextual modifier classes for colorizing the alert
@each $state in map.keys($theme-colors) {
.alert-#{$state} {
--#{$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
position: relative;
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
.alert-heading {
// Specified to prevent conflicts of changing $headings-color
color: inherit;
}
// Provide class for links that match alerts
.alert-link {
font-weight: $alert-link-font-weight;
color: var(--#{$prefix}alert-link-color);
}
// Dismissible alerts
//
// Expand the right padding and account for the close button's positioning.
.alert-dismissible {
padding-right: $alert-dismissible-padding-r;
// Adjust close link position
.btn-close {
position: absolute;
top: 0;
right: 0;
z-index: $stretched-link-z-index + 1;
padding: $alert-padding-y * 1.25 $alert-padding-x;
}
}
// scss-docs-start alert-modifiers
// Generate contextual modifier classes for colorizing the alert
@each $state in map-keys($theme-colors) {
.alert-#{$state} {
--#{$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
+33 -46
View File
@@ -1,51 +1,38 @@
@use "config" as *;
@use "colors" as *;
@use "variables" as *;
@use "mixins/border-radius" as *;
@use "mixins/gradients" as *;
@use "vendor/rfs" as *;
// Base class
//
// Requires one of the contextual, color modifier classes for `color` and
// `background-color`.
// scss-docs-start badge-variables
$badge-font-size: .75em !default;
$badge-font-weight: $font-weight-bold !default;
$badge-color: $white !default;
$badge-padding-y: .35em !default;
$badge-padding-x: .65em !default;
$badge-border-radius: var(--#{$prefix}border-radius) !default;
// scss-docs-end badge-variables
.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
@layer components {
.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: 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: var(--#{$prefix}badge-color);
text-align: center;
white-space: nowrap;
vertical-align: baseline;
@include border-radius(var(--#{$prefix}badge-border-radius));
@include gradient-bg();
display: inline-block;
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: var(--#{$prefix}badge-color);
text-align: center;
white-space: nowrap;
vertical-align: baseline;
@include border-radius(var(--#{$prefix}badge-border-radius));
@include gradient-bg();
// Empty badges collapse automatically
&:empty {
display: none;
}
}
// Quick fix for badges in buttons
.btn .badge {
position: relative;
top: -1px;
// Empty badges collapse automatically
&:empty {
display: none;
}
}
// Quick fix for badges in buttons
.btn .badge {
position: relative;
top: -1px;
}
-7
View File
@@ -1,7 +0,0 @@
$file: "" !default;
/*!
* Bootstrap #{$file} v6.0.0-dev (https://getbootstrap.com/)
* Copyright 2011-2025 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
+33 -56
View File
@@ -1,63 +1,40 @@
@use "sass:string";
@use "config" as *;
@use "variables" as *;
@use "functions" as *;
@use "mixins/border-radius" as *;
@use "vendor/rfs" as *;
.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
// scss-docs-start breadcrumb-variables
$breadcrumb-font-size: null !default;
$breadcrumb-padding-y: 0 !default;
$breadcrumb-padding-x: 0 !default;
$breadcrumb-item-padding-x: .5rem !default;
$breadcrumb-margin-bottom: 1rem !default;
$breadcrumb-bg: null !default;
$breadcrumb-divider-color: var(--#{$prefix}secondary-color) !default;
$breadcrumb-active-color: var(--#{$prefix}secondary-color) !default;
$breadcrumb-divider: string.quote("/") !default;
$breadcrumb-divider-flipped: $breadcrumb-divider !default;
$breadcrumb-border-radius: null !default;
// scss-docs-end breadcrumb-variables
display: flex;
flex-wrap: wrap;
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: var(--#{$prefix}breadcrumb-bg);
@include border-radius(var(--#{$prefix}breadcrumb-border-radius));
}
@layer components {
.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
.breadcrumb-item {
// The separator between breadcrumbs (by default, a forward-slash: "/")
+ .breadcrumb-item {
padding-left: var(--#{$prefix}breadcrumb-item-padding-x);
display: flex;
flex-wrap: wrap;
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: var(--#{$prefix}breadcrumb-bg);
@include border-radius(var(--#{$prefix}breadcrumb-border-radius));
&::before {
float: left; // Suppress inline spacings and underlining of the separator
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)) #{"*/"};
}
}
.breadcrumb-item {
// The separator between breadcrumbs (by default, a forward-slash: "/")
+ .breadcrumb-item {
padding-left: var(--#{$prefix}breadcrumb-item-padding-x);
&::before {
float: left; // Suppress inline spacings and underlining of the separator
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: var(--#{$prefix}breadcrumb-item-active-color);
}
&.active {
color: var(--#{$prefix}breadcrumb-item-active-color);
}
}
+147
View File
@@ -0,0 +1,147 @@
// Make the div behave like a button
.btn-group,
.btn-group-vertical {
position: relative;
display: inline-flex;
vertical-align: middle; // match .btn alignment given font-size hack above
> .btn {
position: relative;
flex: 1 1 auto;
}
// Bring the hover, focused, and "active" buttons to the front to overlay
// the borders properly
> .btn-check:checked + .btn,
> .btn-check:focus + .btn,
> .btn:hover,
> .btn:focus,
> .btn:active,
> .btn.active {
z-index: 1;
}
}
// Optional: Group multiple button groups together for a toolbar
.btn-toolbar {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
.input-group {
width: auto;
}
}
.btn-group {
@include border-radius($btn-border-radius);
// Prevent double borders when buttons are next to each other
> :not(.btn-check:first-child) + .btn,
> .btn-group:not(:first-child) {
margin-left: calc(-1 * #{$btn-border-width}); // 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);
}
// The left radius should be 0 if the button is:
// - the "third or more" child
// - the second child and the previous element isn't `.btn-check` (making it the first child visually)
// - part of a btn-group which isn't the first child
> .btn:nth-child(n + 3),
> :not(.btn-check) + .btn,
> .btn-group:not(:first-child) > .btn {
@include border-start-radius(0);
}
}
// Sizing
//
// Remix the default button sizing classes into new ones for easier manipulation.
.btn-group-sm > .btn { @extend .btn-sm; }
.btn-group-lg > .btn { @extend .btn-lg; }
//
// Split button dropdowns
//
.dropdown-toggle-split {
padding-right: $btn-padding-x * .75;
padding-left: $btn-padding-x * .75;
&::after,
.dropup &::after,
.dropend &::after {
margin-left: 0;
}
.dropstart &::before {
margin-right: 0;
}
}
.btn-sm + .dropdown-toggle-split {
padding-right: $btn-padding-x-sm * .75;
padding-left: $btn-padding-x-sm * .75;
}
.btn-lg + .dropdown-toggle-split {
padding-right: $btn-padding-x-lg * .75;
padding-left: $btn-padding-x-lg * .75;
}
// The clickable button for toggling the menu
// Set the same inset shadow as the :active state
.btn-group.show .dropdown-toggle {
@include box-shadow($btn-active-box-shadow);
// Show no shadow for `.btn-link` since it has no other button styles.
&.btn-link {
@include box-shadow(none);
}
}
//
// Vertical button groups
//
.btn-group-vertical {
flex-direction: column;
align-items: flex-start;
justify-content: center;
> .btn,
> .btn-group {
width: 100%;
}
> .btn:not(:first-child),
> .btn-group:not(:first-child) {
margin-top: calc(-1 * #{$btn-border-width}); // stylelint-disable-line function-disallowed-list
}
// Reset rounded corners
> .btn:not(:last-child):not(.dropdown-toggle),
> .btn-group:not(:last-child) > .btn {
@include border-bottom-radius(0);
}
// The top radius should be 0 if the button is:
// - the "third or more" child
// - the second child and the previous element isn't `.btn-check` (making it the first child visually)
// - part of a btn-group which isn't the first child
> .btn:nth-child(n + 3),
> :not(.btn-check) + .btn,
> .btn-group:not(:first-child) > .btn {
@include border-top-radius(0);
}
}
+216
View File
@@ -0,0 +1,216 @@
//
// Base styles
//
.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;
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;
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: 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 + &: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;
// 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 + &,
: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-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;
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);
}
}
//
// Alternate buttons
//
// scss-docs-start btn-variant-loops
@each $color, $value in $theme-colors {
.btn-#{$color} {
@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);
}
}
}
@each $color, $value in $theme-colors {
.btn-outline-#{$color} {
@include button-outline-variant($value);
}
}
// scss-docs-end btn-variant-loops
//
// Link buttons
//
// Make a button look and behave like a link
.btn-link {
--#{$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: var(--#{$prefix}btn-hover-color);
}
// No need for an active state here
}
//
// Button Sizes
//
.btn-lg {
@include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg);
}
.btn-sm {
@include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm);
}
+205 -231
View File
@@ -1,261 +1,235 @@
@use "config" as *;
@use "variables" as *;
@use "mixins/border-radius" as *;
@use "mixins/box-shadow" as *;
@use "layout/breakpoints" as *;
//
// Base styles
//
// scss-docs-start card-variables
$card-spacer-y: $spacer !default;
$card-spacer-x: $spacer !default;
$card-title-spacer-y: $spacer * .5 !default;
$card-title-color: null !default;
$card-subtitle-color: null !default;
$card-border-width: var(--#{$prefix}border-width) !default;
$card-border-color: var(--#{$prefix}border-color-translucent) !default;
$card-border-radius: var(--#{$prefix}border-radius) !default;
$card-box-shadow: null !default;
$card-inner-border-radius: calc(#{$card-border-radius} - #{$card-border-width}) !default;
$card-cap-padding-y: $card-spacer-y * .5 !default;
$card-cap-padding-x: $card-spacer-x !default;
$card-cap-bg: rgba(var(--#{$prefix}body-color-rgb), .03) !default;
$card-cap-color: null !default;
$card-height: null !default;
$card-color: null !default;
$card-bg: var(--#{$prefix}body-bg) !default;
$card-img-overlay-padding: $spacer !default;
$card-group-margin: $grid-gutter-width * .5 !default;
// scss-docs-end card-variables
.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
@layer components {
.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: var(--#{$prefix}card-height);
color: var(--#{$prefix}body-color);
word-wrap: break-word;
background-color: var(--#{$prefix}card-bg);
background-clip: border-box;
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));
position: relative;
display: flex;
flex-direction: column;
min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106
height: var(--#{$prefix}card-height);
color: var(--#{$prefix}body-color);
word-wrap: break-word;
background-color: var(--#{$prefix}card-bg);
background-clip: border-box;
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;
margin-left: 0;
}
> .list-group {
border-top: inherit;
border-bottom: inherit;
&:first-child {
border-top-width: 0;
@include border-top-radius(var(--#{$prefix}card-inner-border-radius));
}
&:last-child {
border-bottom-width: 0;
@include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));
}
}
// Due to specificity of the above selector (`.card > .list-group`), we must
// use a child selector here to prevent double borders.
> .card-header + .list-group,
> .list-group + .card-footer {
border-top: 0;
}
> hr {
margin-right: 0;
margin-left: 0;
}
.card-body {
// 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: var(--#{$prefix}card-spacer-y) var(--#{$prefix}card-spacer-x);
color: var(--#{$prefix}card-color);
}
.card-title {
margin-bottom: var(--#{$prefix}card-title-spacer-y);
color: var(--#{$prefix}card-title-color);
}
.card-subtitle {
margin-top: calc(-.5 * var(--#{$prefix}card-title-spacer-y));
margin-bottom: 0;
color: var(--#{$prefix}card-subtitle-color);
}
.card-text:last-child {
margin-bottom: 0;
}
.card-link {
&:hover {
text-decoration: if($link-hover-decoration == underline, none, null);
}
+ .card-link {
margin-left: var(--#{$prefix}card-spacer-x);
}
}
//
// Optional textual caps
//
.card-header {
padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x);
margin-bottom: 0; // Removes the default margin-bottom of <hN>
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);
> .list-group {
border-top: inherit;
border-bottom: inherit;
&:first-child {
@include border-radius(var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius) 0 0);
border-top-width: 0;
@include border-top-radius(var(--#{$prefix}card-inner-border-radius));
}
&:last-child {
border-bottom-width: 0;
@include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));
}
}
.card-footer {
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);
// Due to specificity of the above selector (`.card > .list-group`), we must
// use a child selector here to prevent double borders.
> .card-header + .list-group,
> .list-group + .card-footer {
border-top: 0;
}
}
&:last-child {
@include border-radius(0 0 var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius));
}
.card-body {
// 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: var(--#{$prefix}card-spacer-y) var(--#{$prefix}card-spacer-x);
color: var(--#{$prefix}card-color);
}
.card-title {
margin-bottom: var(--#{$prefix}card-title-spacer-y);
color: var(--#{$prefix}card-title-color);
}
.card-subtitle {
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 {
margin-bottom: 0;
}
.card-link {
&:hover {
text-decoration: if($link-hover-decoration == underline, none, null);
}
+ .card-link {
margin-left: var(--#{$prefix}card-spacer-x);
}
}
//
// Header navs
//
//
// Optional textual caps
//
.card-header-tabs {
margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x));
margin-bottom: calc(-1 * var(--#{$prefix}card-cap-padding-y));
margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x));
border-bottom: 0;
.card-header {
padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x);
margin-bottom: 0; // Removes the default margin-bottom of <hN>
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);
.nav-link.active {
background-color: var(--#{$prefix}card-bg);
border-bottom-color: var(--#{$prefix}card-bg);
}
&:first-child {
@include border-radius(var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius) 0 0);
}
}
.card-footer {
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 var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius));
}
}
//
// Header navs
//
.card-header-tabs {
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;
.nav-link.active {
background-color: var(--#{$prefix}card-bg);
border-bottom-color: var(--#{$prefix}card-bg);
}
}
.card-header-pills {
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
.card-img-overlay {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: var(--#{$prefix}card-img-overlay-padding);
@include border-radius(var(--#{$prefix}card-inner-border-radius));
}
.card-img,
.card-img-top,
.card-img-bottom {
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
}
.card-img,
.card-img-top {
@include border-top-radius(var(--#{$prefix}card-inner-border-radius));
}
.card-img,
.card-img-bottom {
@include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));
}
//
// Card groups
//
.card-group {
// The child selector allows nested `.card` within `.card-group`
// to display properly.
> .card {
margin-bottom: var(--#{$prefix}card-group-margin);
}
.card-header-pills {
margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x));
margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x));
}
// Card image
.card-img-overlay {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: var(--#{$prefix}card-img-overlay-padding);
@include border-radius(var(--#{$prefix}card-inner-border-radius));
}
.card-img,
.card-img-top,
.card-img-bottom {
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
}
.card-img,
.card-img-top {
@include border-top-radius(var(--#{$prefix}card-inner-border-radius));
}
.card-img,
.card-img-bottom {
@include border-bottom-radius(var(--#{$prefix}card-inner-border-radius));
}
//
// Card groups
//
.card-group {
@include media-breakpoint-up(sm) {
display: flex;
flex-flow: row wrap;
// The child selector allows nested `.card` within `.card-group`
// to display properly.
> .card {
margin-bottom: var(--#{$prefix}card-group-margin);
}
flex: 1 0 0;
margin-bottom: 0;
@include media-breakpoint-up(sm) {
display: flex;
flex-flow: row wrap;
// The child selector allows nested `.card` within `.card-group`
// to display properly.
> .card {
flex: 1 0 0;
margin-bottom: 0;
+ .card {
margin-left: 0;
border-left: 0;
}
+ .card {
margin-left: 0;
border-left: 0;
// Handle rounded corners
@if $enable-rounded {
&:not(:last-child) {
@include border-end-radius(0);
> .card-img-top,
> .card-header {
// stylelint-disable-next-line property-disallowed-list
border-top-right-radius: 0;
}
> .card-img-bottom,
> .card-footer {
// stylelint-disable-next-line property-disallowed-list
border-bottom-right-radius: 0;
}
}
// Handle rounded corners
@if $enable-rounded {
&:not(:last-child) {
@include border-end-radius(0);
&:not(:first-child) {
@include border-start-radius(0);
> .card-img-top,
> .card-header {
// stylelint-disable-next-line property-disallowed-list
border-top-right-radius: 0;
}
> .card-img-bottom,
> .card-footer {
// stylelint-disable-next-line property-disallowed-list
border-bottom-right-radius: 0;
}
> .card-img-top,
> .card-header {
// stylelint-disable-next-line property-disallowed-list
border-top-left-radius: 0;
}
&:not(:first-child) {
@include border-start-radius(0);
> .card-img-top,
> .card-header {
// stylelint-disable-next-line property-disallowed-list
border-top-left-radius: 0;
}
> .card-img-bottom,
> .card-footer {
// stylelint-disable-next-line property-disallowed-list
border-bottom-left-radius: 0;
}
> .card-img-bottom,
> .card-footer {
// stylelint-disable-next-line property-disallowed-list
border-bottom-left-radius: 0;
}
}
}
+201 -248
View File
@@ -1,48 +1,3 @@
@use "config" as *;
@use "colors" as *;
@use "variables" as *;
@use "mixins/transition" as *;
@use "mixins/gradients" as *;
@use "mixins/color-mode" as *;
@use "vendor/rfs" as *;
// scss-docs-start carousel-variables
$carousel-control-color: $white !default;
$carousel-control-width: 15% !default;
$carousel-control-opacity: .5 !default;
$carousel-control-hover-opacity: .9 !default;
$carousel-control-transition: opacity .15s ease !default;
$carousel-control-icon-filter: null !default;
$carousel-indicator-width: 30px !default;
$carousel-indicator-height: 3px !default;
$carousel-indicator-hit-area-height: 10px !default;
$carousel-indicator-spacer: 3px !default;
$carousel-indicator-opacity: .5 !default;
$carousel-indicator-active-bg: $white !default;
$carousel-indicator-active-opacity: 1 !default;
$carousel-indicator-transition: opacity .6s ease !default;
$carousel-caption-width: 70% !default;
$carousel-caption-color: $white !default;
$carousel-caption-padding-y: 1.25rem !default;
$carousel-caption-spacer: 1.25rem !default;
$carousel-control-icon-width: 2rem !default;
$carousel-control-prev-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$carousel-control-color}'><path d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0'/></svg>") !default;
$carousel-control-next-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$carousel-control-color}'><path d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708'/></svg>") !default;
$carousel-transition-duration: .6s !default;
$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`)
// scss-docs-end carousel-variables
// scss-docs-start carousel-dark-variables
$carousel-indicator-active-bg-dark: $black !default;
$carousel-caption-color-dark: $black !default;
$carousel-control-icon-filter-dark: invert(1) grayscale(100) !default;
// scss-docs-end carousel-dark-variables
// Notes on the classes:
//
// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically)
@@ -56,218 +11,216 @@ $carousel-control-icon-filter-dark: invert(1) grayscale(100) !default;
// 5. .carousel-item-next.carousel-item-start and .carousel-item-prev.carousel-item-end
// is the upcoming slide in transition.
@layer components {
.carousel {
position: relative;
}
.carousel {
position: relative;
}
.carousel.pointer-event {
touch-action: pan-y;
}
.carousel.pointer-event {
touch-action: pan-y;
}
.carousel-inner {
position: relative;
display: flow-root;
width: 100%;
overflow: hidden;
}
.carousel-inner {
position: relative;
width: 100%;
overflow: hidden;
@include clearfix();
}
.carousel-item {
position: relative;
display: none;
float: left;
width: 100%;
margin-right: -100%;
backface-visibility: hidden;
@include transition($carousel-transition);
}
.carousel-item.active,
.carousel-item-next,
.carousel-item-prev {
display: block;
}
.carousel-item-next:not(.carousel-item-start),
.active.carousel-item-end {
transform: translateX(100%);
}
.carousel-item-prev:not(.carousel-item-end),
.active.carousel-item-start {
transform: translateX(-100%);
}
//
// Alternate transitions
//
.carousel-fade {
.carousel-item {
position: relative;
display: none;
float: left;
width: 100%;
margin-right: -100%;
backface-visibility: hidden;
@include transition($carousel-transition);
opacity: 0;
transition-property: opacity;
transform: none;
}
.carousel-item.active,
.carousel-item-next,
.carousel-item-prev {
display: block;
}
.carousel-item-next:not(.carousel-item-start),
.active.carousel-item-end {
transform: translateX(100%);
}
.carousel-item-prev:not(.carousel-item-end),
.active.carousel-item-start {
transform: translateX(-100%);
}
//
// Alternate transitions
//
.carousel-fade {
.carousel-item {
opacity: 0;
transition-property: opacity;
transform: none;
}
.carousel-item.active,
.carousel-item-next.carousel-item-start,
.carousel-item-prev.carousel-item-end {
z-index: 1;
opacity: 1;
}
.active.carousel-item-start,
.active.carousel-item-end {
z-index: 0;
opacity: 0;
@include transition(opacity 0s $carousel-transition-duration);
}
}
//
// Left/right controls for nav
//
.carousel-control-prev,
.carousel-control-next {
position: absolute;
top: 0;
bottom: 0;
.carousel-item-next.carousel-item-start,
.carousel-item-prev.carousel-item-end {
z-index: 1;
// Use flex for alignment (1-3)
display: flex; // 1. allow flex styles
align-items: center; // 2. vertically center contents
justify-content: center; // 3. horizontally center contents
width: $carousel-control-width;
padding: 0;
color: $carousel-control-color;
text-align: center;
background: none;
filter: var(--#{$prefix}carousel-control-icon-filter);
border: 0;
opacity: $carousel-control-opacity;
@include transition($carousel-control-transition);
// Hover/focus state
&:hover,
&:focus {
color: $carousel-control-color;
text-decoration: none;
outline: 0;
opacity: $carousel-control-hover-opacity;
}
}
.carousel-control-prev {
left: 0;
background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null);
}
.carousel-control-next {
right: 0;
background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null);
opacity: 1;
}
// Icons for within
.carousel-control-prev-icon,
.carousel-control-next-icon {
display: inline-block;
width: $carousel-control-icon-width;
height: $carousel-control-icon-width;
background-repeat: no-repeat;
background-position: 50%;
background-size: 100% 100%;
}
.carousel-control-prev-icon {
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) #{"/*rtl:" + escape-svg($carousel-control-prev-icon-bg) + "*/"};
}
// Optional indicator pips/controls
//
// Add a container (such as a list) with the following class and add an item (ideally a focusable control,
// like a button) with data-bs-target for each slide your carousel holds.
.carousel-indicators {
position: absolute;
right: 0;
bottom: 0;
left: 0;
z-index: 2;
display: flex;
justify-content: center;
padding: 0;
// Use the .carousel-control's width as margin so we don't overlay those
margin-right: $carousel-control-width;
margin-bottom: 1rem;
margin-left: $carousel-control-width;
[data-bs-target] {
box-sizing: content-box;
flex: 0 1 auto;
width: $carousel-indicator-width;
height: $carousel-indicator-height;
padding: 0;
margin-right: $carousel-indicator-spacer;
margin-left: $carousel-indicator-spacer;
text-indent: -999px;
cursor: pointer;
background-color: var(--#{$prefix}carousel-indicator-active-bg);
background-clip: padding-box;
border: 0;
// Use transparent borders to increase the hit area by 10px on top and bottom.
border-top: $carousel-indicator-hit-area-height solid transparent;
border-bottom: $carousel-indicator-hit-area-height solid transparent;
opacity: $carousel-indicator-opacity;
@include transition($carousel-indicator-transition);
}
.active {
opacity: $carousel-indicator-active-opacity;
}
}
// Optional captions
//
//
.carousel-caption {
position: absolute;
right: (100% - $carousel-caption-width) * .5;
bottom: $carousel-caption-spacer;
left: (100% - $carousel-caption-width) * .5;
padding-top: $carousel-caption-padding-y;
padding-bottom: $carousel-caption-padding-y;
color: var(--#{$prefix}carousel-caption-color);
text-align: center;
}
// Dark mode carousel
@mixin carousel-dark() {
--#{$prefix}carousel-indicator-active-bg: #{$carousel-indicator-active-bg-dark};
--#{$prefix}carousel-caption-color: #{$carousel-caption-color-dark};
--#{$prefix}carousel-control-icon-filter: #{$carousel-control-icon-filter-dark};
}
.carousel-dark {
@include carousel-dark();
}
:root,
[data-bs-theme="light"] {
--#{$prefix}carousel-indicator-active-bg: #{$carousel-indicator-active-bg};
--#{$prefix}carousel-caption-color: #{$carousel-caption-color};
--#{$prefix}carousel-control-icon-filter: #{$carousel-control-icon-filter};
}
@if $enable-dark-mode {
@include color-mode(dark, true) {
@include carousel-dark();
}
.active.carousel-item-start,
.active.carousel-item-end {
z-index: 0;
opacity: 0;
@include transition(opacity 0s $carousel-transition-duration);
}
}
//
// Left/right controls for nav
//
.carousel-control-prev,
.carousel-control-next {
position: absolute;
top: 0;
bottom: 0;
z-index: 1;
// Use flex for alignment (1-3)
display: flex; // 1. allow flex styles
align-items: center; // 2. vertically center contents
justify-content: center; // 3. horizontally center contents
width: $carousel-control-width;
padding: 0;
color: $carousel-control-color;
text-align: center;
background: none;
filter: var(--#{$prefix}carousel-control-icon-filter);
border: 0;
opacity: $carousel-control-opacity;
@include transition($carousel-control-transition);
// Hover/focus state
&:hover,
&:focus {
color: $carousel-control-color;
text-decoration: none;
outline: 0;
opacity: $carousel-control-hover-opacity;
}
}
.carousel-control-prev {
left: 0;
background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null);
}
.carousel-control-next {
right: 0;
background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null);
}
// Icons for within
.carousel-control-prev-icon,
.carousel-control-next-icon {
display: inline-block;
width: $carousel-control-icon-width;
height: $carousel-control-icon-width;
background-repeat: no-repeat;
background-position: 50%;
background-size: 100% 100%;
}
.carousel-control-prev-icon {
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) #{"/*rtl:" + escape-svg($carousel-control-prev-icon-bg) + "*/"};
}
// Optional indicator pips/controls
//
// Add a container (such as a list) with the following class and add an item (ideally a focusable control,
// like a button) with data-bs-target for each slide your carousel holds.
.carousel-indicators {
position: absolute;
right: 0;
bottom: 0;
left: 0;
z-index: 2;
display: flex;
justify-content: center;
padding: 0;
// Use the .carousel-control's width as margin so we don't overlay those
margin-right: $carousel-control-width;
margin-bottom: 1rem;
margin-left: $carousel-control-width;
[data-bs-target] {
box-sizing: content-box;
flex: 0 1 auto;
width: $carousel-indicator-width;
height: $carousel-indicator-height;
padding: 0;
margin-right: $carousel-indicator-spacer;
margin-left: $carousel-indicator-spacer;
text-indent: -999px;
cursor: pointer;
background-color: var(--#{$prefix}carousel-indicator-active-bg);
background-clip: padding-box;
border: 0;
// Use transparent borders to increase the hit area by 10px on top and bottom.
border-top: $carousel-indicator-hit-area-height solid transparent;
border-bottom: $carousel-indicator-hit-area-height solid transparent;
opacity: $carousel-indicator-opacity;
@include transition($carousel-indicator-transition);
}
.active {
opacity: $carousel-indicator-active-opacity;
}
}
// Optional captions
//
//
.carousel-caption {
position: absolute;
right: (100% - $carousel-caption-width) * .5;
bottom: $carousel-caption-spacer;
left: (100% - $carousel-caption-width) * .5;
padding-top: $carousel-caption-padding-y;
padding-bottom: $carousel-caption-padding-y;
color: var(--#{$prefix}carousel-caption-color);
text-align: center;
}
// Dark mode carousel
@mixin carousel-dark() {
--#{$prefix}carousel-indicator-active-bg: #{$carousel-indicator-active-bg-dark};
--#{$prefix}carousel-caption-color: #{$carousel-caption-color-dark};
--#{$prefix}carousel-control-icon-filter: #{$carousel-control-icon-filter-dark};
}
.carousel-dark {
@include carousel-dark();
}
:root,
[data-bs-theme="light"] {
--#{$prefix}carousel-indicator-active-bg: #{$carousel-indicator-active-bg};
--#{$prefix}carousel-caption-color: #{$carousel-caption-color};
--#{$prefix}carousel-control-icon-filter: #{$carousel-control-icon-filter};
}
@if $enable-dark-mode {
@include color-mode(dark, true) {
@include carousel-dark();
}
}
+66
View File
@@ -0,0 +1,66 @@
// 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};
// 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: var(--#{$prefix}btn-close-color);
background: transparent var(--#{$prefix}btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements
filter: var(--#{$prefix}btn-close-filter);
border: 0; // for button elements
@include border-radius();
opacity: var(--#{$prefix}btn-close-opacity);
// Override <a>'s hover style
&:hover {
color: var(--#{$prefix}btn-close-color);
text-decoration: none;
opacity: var(--#{$prefix}btn-close-hover-opacity);
}
&:focus {
outline: 0;
box-shadow: var(--#{$prefix}btn-close-focus-shadow);
opacity: var(--#{$prefix}btn-close-focus-opacity);
}
&:disabled,
&.disabled {
pointer-events: none;
user-select: none;
opacity: var(--#{$prefix}btn-close-disabled-opacity);
}
}
@mixin btn-close-white() {
--#{$prefix}btn-close-filter: #{$btn-close-filter-dark};
}
.btn-close-white {
@include btn-close-white();
}
:root,
[data-bs-theme="light"] {
--#{$prefix}btn-close-filter: #{$btn-close-filter};
}
@if $enable-dark-mode {
@include color-mode(dark, true) {
@include btn-close-white();
}
}
-282
View File
@@ -1,282 +0,0 @@
$blue: #0d6efd !default;
$blue-100: #cfe2ff !default;
$blue-200: #9ec5fe !default;
$blue-300: #6ea8fe !default;
$blue-400: #3d8bfd !default;
$blue-500: $blue !default;
$blue-600: #0a58ca !default;
$blue-700: #084298 !default;
$blue-800: #052c65 !default;
$blue-900: #031633 !default;
$indigo: #6610f2 !default;
$indigo-100: #e0cffc !default;
$indigo-200: #c29ffa !default;
$indigo-300: #a370f7 !default;
$indigo-400: #8540f5 !default;
$indigo-500: $indigo !default;
$indigo-600: #520dc2 !default;
$indigo-700: #3d0a91 !default;
$indigo-800: #290661 !default;
$indigo-900: #140330 !default;
$purple: #6f42c1 !default;
$purple-100: #e2d9f3 !default;
$purple-200: #c5b3e6 !default;
$purple-300: #a98eda !default;
$purple-400: #8c68cd !default;
$purple-500: $purple !default;
$purple-600: #59359a !default;
$purple-700: #432874 !default;
$purple-800: #2c1a4d !default;
$purple-900: #160d27 !default;
$pink: #d63384 !default;
$pink-100: #f7d6e6 !default;
$pink-200: #efadce !default;
$pink-300: #e685b5 !default;
$pink-400: #de5c9d !default;
$pink-500: $pink !default;
$pink-600: #ab296a !default;
$pink-700: #801f4f !default;
$pink-800: #561435 !default;
$pink-900: #2b0a1a !default;
$red: #dc3545 !default;
$red-100: #f8d7da !default;
$red-200: #f1aeb5 !default;
$red-300: #ea868f !default;
$red-400: #e35d6a !default;
$red-500: $red !default;
$red-600: #b02a37 !default;
$red-700: #842029 !default;
$red-800: #58151c !default;
$red-900: #2c0b0e !default;
$orange: #fd7e14 !default;
$orange-100: #ffe5d0 !default;
$orange-200: #fecba1 !default;
$orange-300: #feb272 !default;
$orange-400: #fd9843 !default;
$orange-500: $orange !default;
$orange-600: #ca6510 !default;
$orange-700: #984c0c !default;
$orange-800: #653208 !default;
$orange-900: #331904 !default;
$yellow: #ffc107 !default;
$yellow-100: #fff3cd !default;
$yellow-200: #ffe69c !default;
$yellow-300: #ffda6a !default;
$yellow-400: #ffcd39 !default;
$yellow-500: $yellow !default;
$yellow-600: #cc9a06 !default;
$yellow-700: #997404 !default;
$yellow-800: #664d03 !default;
$yellow-900: #332701 !default;
$green: #198754 !default;
$green-100: #d1e7dd !default;
$green-200: #a3cfbb !default;
$green-300: #75b798 !default;
$green-400: #479f76 !default;
$green-500: $green !default;
$green-600: #146c43 !default;
$green-700: #0f5132 !default;
$green-800: #0a3622 !default;
$green-900: #051b11 !default;
$teal: #20c997 !default;
$teal-100: #d2f4ea !default;
$teal-200: #a6e9d5 !default;
$teal-300: #79dfc1 !default;
$teal-400: #4dd4ac !default;
$teal-500: $teal !default;
$teal-600: #1aa179 !default;
$teal-700: #13795b !default;
$teal-800: #0d503c !default;
$teal-900: #06281e !default;
$cyan: #0dcaf0 !default;
$cyan-100: #cff4fc !default;
$cyan-200: #9eeaf9 !default;
$cyan-300: #6edff6 !default;
$cyan-400: #3dd5f3 !default;
$cyan-500: $cyan !default;
$cyan-600: #0aa2c0 !default;
$cyan-700: #087990 !default;
$cyan-800: #055160 !default;
$cyan-900: #032830 !default;
$gray: #adb5bd !default;
$gray-100: #f8f9fa !default;
$gray-200: #e9ecef !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: $gray !default;
$gray-600: #6c757d !default;
$gray-700: #495057 !default;
$gray-800: #343a40 !default;
$gray-900: #212529 !default;
$white: #fff !default;
$black: #000 !default;
$blues: (
"blue-100": $blue-100,
"blue-200": $blue-200,
"blue-300": $blue-300,
"blue-400": $blue-400,
"blue-500": $blue-500,
"blue-600": $blue-600,
"blue-700": $blue-700,
"blue-800": $blue-800,
"blue-900": $blue-900
) !default;
$indigos: (
"indigo-100": $indigo-100,
"indigo-200": $indigo-200,
"indigo-300": $indigo-300,
"indigo-400": $indigo-400,
"indigo-500": $indigo-500,
"indigo-600": $indigo-600,
"indigo-700": $indigo-700,
"indigo-800": $indigo-800,
"indigo-900": $indigo-900
) !default;
$purples: (
"purple-100": $purple-100,
"purple-200": $purple-200,
"purple-300": $purple-300,
"purple-400": $purple-400,
"purple-500": $purple-500,
"purple-600": $purple-600,
"purple-700": $purple-700,
"purple-800": $purple-800,
"purple-900": $purple-900
) !default;
$pinks: (
"pink-100": $pink-100,
"pink-200": $pink-200,
"pink-300": $pink-300,
"pink-400": $pink-400,
"pink-500": $pink-500,
"pink-600": $pink-600,
"pink-700": $pink-700,
"pink-800": $pink-800,
"pink-900": $pink-900
) !default;
$reds: (
"red-100": $red-100,
"red-200": $red-200,
"red-300": $red-300,
"red-400": $red-400,
"red-500": $red-500,
"red-600": $red-600,
"red-700": $red-700,
"red-800": $red-800,
"red-900": $red-900
) !default;
$oranges: (
"orange-100": $orange-100,
"orange-200": $orange-200,
"orange-300": $orange-300,
"orange-400": $orange-400,
"orange-500": $orange-500,
"orange-600": $orange-600,
"orange-700": $orange-700,
"orange-800": $orange-800,
"orange-900": $orange-900
) !default;
$yellows: (
"yellow-100": $yellow-100,
"yellow-200": $yellow-200,
"yellow-300": $yellow-300,
"yellow-400": $yellow-400,
"yellow-500": $yellow-500,
"yellow-600": $yellow-600,
"yellow-700": $yellow-700,
"yellow-800": $yellow-800,
"yellow-900": $yellow-900
) !default;
$greens: (
"green-100": $green-100,
"green-200": $green-200,
"green-300": $green-300,
"green-400": $green-400,
"green-500": $green-500,
"green-600": $green-600,
"green-700": $green-700,
"green-800": $green-800,
"green-900": $green-900
) !default;
$teals: (
"teal-100": $teal-100,
"teal-200": $teal-200,
"teal-300": $teal-300,
"teal-400": $teal-400,
"teal-500": $teal-500,
"teal-600": $teal-600,
"teal-700": $teal-700,
"teal-800": $teal-800,
"teal-900": $teal-900
) !default;
$cyans: (
"cyan-100": $cyan-100,
"cyan-200": $cyan-200,
"cyan-300": $cyan-300,
"cyan-400": $cyan-400,
"cyan-500": $cyan-500,
"cyan-600": $cyan-600,
"cyan-700": $cyan-700,
"cyan-800": $cyan-800,
"cyan-900": $cyan-900
) !default;
$grays: (
"gray-100": $gray-100,
"gray-200": $gray-200,
"gray-300": $gray-300,
"gray-400": $gray-400,
"gray-500": $gray-500,
"gray-600": $gray-600,
"gray-700": $gray-700,
"gray-800": $gray-800,
"gray-900": $gray-900
) !default;
$colors: (
"blue": $blue,
"indigo": $indigo,
"purple": $purple,
"pink": $pink,
"red": $red,
"orange": $orange,
"yellow": $yellow,
"green": $green,
"teal": $teal,
"cyan": $cyan
) !default;
$all-colors: (
"grays": $grays,
"blues": $blues,
"indigos": $indigos,
"purples": $purples,
"pinks": $pinks,
"reds": $reds,
"oranges": $oranges,
"yellows": $yellows,
"greens": $greens,
"teals": $teals,
"cyans": $cyans
) !default;
-99
View File
@@ -1,99 +0,0 @@
// Configuration
//
// Variables and settings not related to theme, components, and more go here. It does include layout.
$prefix: bs- !default;
$enable-caret: true !default;
$enable-rounded: true !default;
$enable-shadows: false !default;
$enable-gradients: false !default;
$enable-transitions: true !default;
$enable-reduced-motion: true !default;
$enable-smooth-scroll: true !default;
$enable-grid-classes: true !default;
$enable-container-classes: true !default;
$enable-cssgrid: true !default;
$enable-button-pointers: true !default;
$enable-rfs: true !default;
$enable-validation-icons: true !default;
$enable-negative-margins: false !default;
$enable-deprecation-messages: true !default;
$enable-dark-mode: true !default;
$color-mode-type: data !default; // `data` or `media-query`
// more to come here
$color-mode-type: "media-query" !default;
$color-contrast-dark: #000 !default;
$color-contrast-light: #fff !default;
$min-contrast-ratio: 4.5 !default;
// scss-docs-start spacer-variables-maps
$spacer: 1rem !default;
$spacers: (
0: 0,
1: $spacer * .25,
2: $spacer * .5,
3: $spacer,
4: $spacer * 1.5,
5: $spacer * 3,
) !default;
// scss-docs-end spacer-variables-maps
// Grid breakpoints
//
// Define the minimum dimensions at which your layout will change,
// adapting to different screen sizes, for use in media queries.
// scss-docs-start grid-breakpoints
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px
) !default;
// scss-docs-end grid-breakpoints
// @include _assert-ascending($grid-breakpoints, "$grid-breakpoints");
// @include _assert-starts-at-zero($grid-breakpoints, "$grid-breakpoints");
// Grid columns
//
// Set the number of columns and specify the width of the gutters.
$grid-columns: 12 !default;
$grid-gutter-width: 1.5rem !default;
$grid-row-columns: 6 !default;
$gutters: $spacers !default;
// Grid containers
//
// Define the maximum width of `.container` for different screen sizes.
// scss-docs-start container-max-widths
$container-max-widths: (
sm: 540px,
md: 720px,
lg: 960px,
xl: 1140px,
xxl: 1320px
) !default;
// scss-docs-end container-max-widths
$container-padding-x: $grid-gutter-width !default;
$utilities: () !default;
// Characters which are escaped by the escape-svg function
$escaped-characters: (
("<", "%3c"),
(">", "%3e"),
("#", "%23"),
("(", "%28"),
(")", "%29"),
) !default;
+41
View File
@@ -0,0 +1,41 @@
// Container widths
//
// Set the container width, and override it for fixed navbars in media queries.
@if $enable-container-classes {
// Single container class with breakpoint max-widths
.container,
// 100% wide container at all breakpoints
.container-fluid {
@include make-container();
}
// Responsive containers that are 100% wide until a breakpoint
@each $breakpoint, $container-max-width in $container-max-widths {
.container-#{$breakpoint} {
@extend .container-fluid;
}
@include media-breakpoint-up($breakpoint, $grid-breakpoints) {
%responsive-container-#{$breakpoint} {
max-width: $container-max-width;
}
// Extend each breakpoint which is smaller or equal to the current breakpoint
$extend-breakpoint: true;
@each $name, $width in $grid-breakpoints {
@if ($extend-breakpoint) {
.container#{breakpoint-infix($name, $grid-breakpoints)} {
@extend %responsive-container-#{$breakpoint};
}
// Once the current breakpoint is reached, stop extending
@if ($breakpoint == $name) {
$extend-breakpoint: false;
}
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More