+++ /dev/null
-/*!
- * Bootstrap focustrap.js v6.0.0-alpha1 (https://getbootstrap.com/)
- * Copyright 2011-2026 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
- */
-import EventHandler from '../dom/event-handler.js';
-import SelectorEngine from '../dom/selector-engine.js';
-import Config from './config.js';
-
-/**
- * --------------------------------------------------------------------------
- * Bootstrap util/focustrap.js
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
- * --------------------------------------------------------------------------
- */
-
-
-/**
- * Constants
- */
-
-const NAME = 'focustrap';
-const DATA_KEY = 'bs.focustrap';
-const EVENT_KEY = `.${DATA_KEY}`;
-const EVENT_FOCUSIN = `focusin${EVENT_KEY}`;
-const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`;
-const TAB_KEY = 'Tab';
-const TAB_NAV_FORWARD = 'forward';
-const TAB_NAV_BACKWARD = 'backward';
-const Default = {
- autofocus: true,
- trapElement: null // The element to trap focus inside of
-};
-const DefaultType = {
- autofocus: 'boolean',
- trapElement: 'element'
-};
-
-/**
- * Class definition
- */
-
-class FocusTrap extends Config {
- constructor(config) {
- super();
- this._config = this._getConfig(config);
- this._isActive = false;
- this._lastTabNavDirection = null;
- }
-
- // Getters
- static get Default() {
- return Default;
- }
- static get DefaultType() {
- return DefaultType;
- }
- static get NAME() {
- return NAME;
- }
-
- // Public
- activate() {
- if (this._isActive) {
- return;
- }
- if (this._config.autofocus) {
- this._config.trapElement.focus();
- }
- EventHandler.off(document, EVENT_KEY); // guard against infinite focus loop
- EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event));
- EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));
- this._isActive = true;
- }
- deactivate() {
- if (!this._isActive) {
- return;
- }
- this._isActive = false;
- EventHandler.off(document, EVENT_KEY);
- }
-
- // Private
- _handleFocusin(event) {
- const {
- trapElement
- } = this._config;
- if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {
- return;
- }
- const elements = SelectorEngine.focusableChildren(trapElement);
- if (elements.length === 0) {
- trapElement.focus();
- } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
- elements.at(-1).focus();
- } else {
- elements[0].focus();
- }
- }
- _handleKeydown(event) {
- if (event.key !== TAB_KEY) {
- return;
- }
- this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;
- }
-}
-
-export { FocusTrap as default };
-//# sourceMappingURL=focustrap.js.map
+++ /dev/null
-{"version":3,"file":"focustrap.js","sources":["../../src/util/focustrap.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nconst Default = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n}\n\nconst DefaultType = {\n autofocus: 'boolean',\n trapElement: 'element'\n}\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\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 // Public\n activate() {\n if (this._isActive) {\n return\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n _handleFocusin(event) {\n const { trapElement } = this._config\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements.at(-1).focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n}\n\nexport default FocusTrap\n"],"names":["NAME","DATA_KEY","EVENT_KEY","EVENT_FOCUSIN","EVENT_KEYDOWN_TAB","TAB_KEY","TAB_NAV_FORWARD","TAB_NAV_BACKWARD","Default","autofocus","trapElement","DefaultType","FocusTrap","Config","constructor","config","_config","_getConfig","_isActive","_lastTabNavDirection","activate","focus","EventHandler","off","document","on","event","_handleFocusin","_handleKeydown","deactivate","target","contains","elements","SelectorEngine","focusableChildren","length","at","key","shiftKey"],"mappings":"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"}
\ No newline at end of file
+++ /dev/null
-/*!
- * Bootstrap scrollbar.js v6.0.0-alpha1 (https://getbootstrap.com/)
- * Copyright 2011-2026 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
- */
-import Manipulator from '../dom/manipulator.js';
-import SelectorEngine from '../dom/selector-engine.js';
-import { isElement } from './index.js';
-
-/**
- * --------------------------------------------------------------------------
- * Bootstrap util/scrollBar.js
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
- * --------------------------------------------------------------------------
- */
-
-
-/**
- * Constants
- */
-
-const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
-const SELECTOR_STICKY_CONTENT = '.sticky-top';
-const PROPERTY_PADDING = 'padding-right';
-const PROPERTY_MARGIN = 'margin-right';
-
-/**
- * Class definition
- */
-
-class ScrollBarHelper {
- constructor() {
- this._element = document.body;
- }
-
- // Public
- getWidth() {
- // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
- const documentWidth = document.documentElement.clientWidth;
- return Math.abs(window.innerWidth - documentWidth);
- }
- hide() {
- const width = this.getWidth();
- this._disableOverFlow();
- // give padding to element to balance the hidden scrollbar width
- this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width);
- // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
- this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width);
- this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width);
- }
- reset() {
- this._resetElementAttributes(this._element, 'overflow');
- this._resetElementAttributes(this._element, PROPERTY_PADDING);
- this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING);
- this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN);
- }
- isOverflowing() {
- return this.getWidth() > 0;
- }
-
- // Private
- _disableOverFlow() {
- this._saveInitialAttribute(this._element, 'overflow');
- this._element.style.overflow = 'hidden';
- }
- _setElementAttributes(selector, styleProperty, callback) {
- const scrollbarWidth = this.getWidth();
- const manipulationCallBack = element => {
- if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
- return;
- }
- this._saveInitialAttribute(element, styleProperty);
- const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty);
- element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`);
- };
- this._applyManipulationCallback(selector, manipulationCallBack);
- }
- _saveInitialAttribute(element, styleProperty) {
- const actualValue = element.style.getPropertyValue(styleProperty);
- if (actualValue) {
- Manipulator.setDataAttribute(element, styleProperty, actualValue);
- }
- }
- _resetElementAttributes(selector, styleProperty) {
- const manipulationCallBack = element => {
- const value = Manipulator.getDataAttribute(element, styleProperty);
- // We only want to remove the property if the value is `null`; the value can also be zero
- if (value === null) {
- element.style.removeProperty(styleProperty);
- return;
- }
- Manipulator.removeDataAttribute(element, styleProperty);
- element.style.setProperty(styleProperty, value);
- };
- this._applyManipulationCallback(selector, manipulationCallBack);
- }
- _applyManipulationCallback(selector, callBack) {
- if (isElement(selector)) {
- callBack(selector);
- return;
- }
- for (const sel of SelectorEngine.find(selector, this._element)) {
- callBack(sel);
- }
- }
-}
-
-export { ScrollBarHelper as default };
-//# sourceMappingURL=scrollbar.js.map
+++ /dev/null
-{"version":3,"file":"scrollbar.js","sources":["../../src/util/scrollbar.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\nconst PROPERTY_PADDING = 'padding-right'\nconst PROPERTY_MARGIN = 'margin-right'\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProperty)\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty)\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty)\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty)\n return\n }\n\n Manipulator.removeDataAttribute(element, styleProperty)\n element.style.setProperty(styleProperty, value)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n return\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel)\n }\n }\n}\n\nexport default ScrollBarHelper\n"],"names":["SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","PROPERTY_PADDING","PROPERTY_MARGIN","ScrollBarHelper","constructor","_element","document","body","getWidth","documentWidth","documentElement","clientWidth","Math","abs","window","innerWidth","hide","width","_disableOverFlow","_setElementAttributes","calculatedValue","reset","_resetElementAttributes","isOverflowing","_saveInitialAttribute","style","overflow","selector","styleProperty","callback","scrollbarWidth","manipulationCallBack","element","getComputedStyle","getPropertyValue","setProperty","Number","parseFloat","_applyManipulationCallback","actualValue","Manipulator","setDataAttribute","value","getDataAttribute","removeProperty","removeDataAttribute","callBack","isElement","sel","SelectorEngine","find"],"mappings":"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"}
\ No newline at end of file
+++ /dev/null
-/**
- * --------------------------------------------------------------------------
- * Bootstrap util/focustrap.js
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
- * --------------------------------------------------------------------------
- */
-
-import EventHandler from '../dom/event-handler.js'
-import SelectorEngine from '../dom/selector-engine.js'
-import Config from './config.js'
-
-/**
- * Constants
- */
-
-const NAME = 'focustrap'
-const DATA_KEY = 'bs.focustrap'
-const EVENT_KEY = `.${DATA_KEY}`
-const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
-const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`
-
-const TAB_KEY = 'Tab'
-const TAB_NAV_FORWARD = 'forward'
-const TAB_NAV_BACKWARD = 'backward'
-
-const Default = {
- autofocus: true,
- trapElement: null // The element to trap focus inside of
-}
-
-const DefaultType = {
- autofocus: 'boolean',
- trapElement: 'element'
-}
-
-/**
- * Class definition
- */
-
-class FocusTrap extends Config {
- constructor(config) {
- super()
- this._config = this._getConfig(config)
- this._isActive = false
- this._lastTabNavDirection = null
- }
-
- // Getters
- static get Default() {
- return Default
- }
-
- static get DefaultType() {
- return DefaultType
- }
-
- static get NAME() {
- return NAME
- }
-
- // Public
- activate() {
- if (this._isActive) {
- return
- }
-
- if (this._config.autofocus) {
- this._config.trapElement.focus()
- }
-
- EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop
- EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))
- EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))
-
- this._isActive = true
- }
-
- deactivate() {
- if (!this._isActive) {
- return
- }
-
- this._isActive = false
- EventHandler.off(document, EVENT_KEY)
- }
-
- // Private
- _handleFocusin(event) {
- const { trapElement } = this._config
-
- if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {
- return
- }
-
- const elements = SelectorEngine.focusableChildren(trapElement)
-
- if (elements.length === 0) {
- trapElement.focus()
- } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
- elements.at(-1).focus()
- } else {
- elements[0].focus()
- }
- }
-
- _handleKeydown(event) {
- if (event.key !== TAB_KEY) {
- return
- }
-
- this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD
- }
-}
-
-export default FocusTrap
+++ /dev/null
-/**
- * --------------------------------------------------------------------------
- * Bootstrap util/scrollBar.js
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
- * --------------------------------------------------------------------------
- */
-
-import Manipulator from '../dom/manipulator.js'
-import SelectorEngine from '../dom/selector-engine.js'
-import { isElement } from './index.js'
-
-/**
- * Constants
- */
-
-const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'
-const SELECTOR_STICKY_CONTENT = '.sticky-top'
-const PROPERTY_PADDING = 'padding-right'
-const PROPERTY_MARGIN = 'margin-right'
-
-/**
- * Class definition
- */
-
-class ScrollBarHelper {
- constructor() {
- this._element = document.body
- }
-
- // Public
- getWidth() {
- // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
- const documentWidth = document.documentElement.clientWidth
- return Math.abs(window.innerWidth - documentWidth)
- }
-
- hide() {
- const width = this.getWidth()
- this._disableOverFlow()
- // give padding to element to balance the hidden scrollbar width
- this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)
- // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
- this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)
- this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)
- }
-
- reset() {
- this._resetElementAttributes(this._element, 'overflow')
- this._resetElementAttributes(this._element, PROPERTY_PADDING)
- this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)
- this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)
- }
-
- isOverflowing() {
- return this.getWidth() > 0
- }
-
- // Private
- _disableOverFlow() {
- this._saveInitialAttribute(this._element, 'overflow')
- this._element.style.overflow = 'hidden'
- }
-
- _setElementAttributes(selector, styleProperty, callback) {
- const scrollbarWidth = this.getWidth()
- const manipulationCallBack = element => {
- if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
- return
- }
-
- this._saveInitialAttribute(element, styleProperty)
- const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)
- element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)
- }
-
- this._applyManipulationCallback(selector, manipulationCallBack)
- }
-
- _saveInitialAttribute(element, styleProperty) {
- const actualValue = element.style.getPropertyValue(styleProperty)
- if (actualValue) {
- Manipulator.setDataAttribute(element, styleProperty, actualValue)
- }
- }
-
- _resetElementAttributes(selector, styleProperty) {
- const manipulationCallBack = element => {
- const value = Manipulator.getDataAttribute(element, styleProperty)
- // We only want to remove the property if the value is `null`; the value can also be zero
- if (value === null) {
- element.style.removeProperty(styleProperty)
- return
- }
-
- Manipulator.removeDataAttribute(element, styleProperty)
- element.style.setProperty(styleProperty, value)
- }
-
- this._applyManipulationCallback(selector, manipulationCallBack)
- }
-
- _applyManipulationCallback(selector, callBack) {
- if (isElement(selector)) {
- callBack(selector)
- return
- }
-
- for (const sel of SelectorEngine.find(selector, this._element)) {
- callBack(sel)
- }
- }
-}
-
-export default ScrollBarHelper
+++ /dev/null
-import EventHandler from '../../../src/dom/event-handler.js'
-import SelectorEngine from '../../../src/dom/selector-engine.js'
-import FocusTrap from '../../../src/util/focustrap.js'
-import { clearFixture, createEvent, getFixture } from '../../helpers/fixture.js'
-
-describe('FocusTrap', () => {
- let fixtureEl
-
- beforeAll(() => {
- fixtureEl = getFixture()
- })
-
- afterEach(() => {
- clearFixture()
- })
-
- describe('activate', () => {
- it('should autofocus itself by default', () => {
- fixtureEl.innerHTML = '<div id="focustrap" tabindex="-1"></div>'
-
- const trapElement = fixtureEl.querySelector('div')
-
- const spy = spyOn(trapElement, 'focus')
-
- const focustrap = new FocusTrap({ trapElement })
- focustrap.activate()
-
- expect(spy).toHaveBeenCalled()
- })
-
- it('if configured not to autofocus, should not autofocus itself', () => {
- fixtureEl.innerHTML = '<div id="focustrap" tabindex="-1"></div>'
-
- const trapElement = fixtureEl.querySelector('div')
-
- const spy = spyOn(trapElement, 'focus')
-
- const focustrap = new FocusTrap({ trapElement, autofocus: false })
- focustrap.activate()
-
- expect(spy).not.toHaveBeenCalled()
- })
-
- it('should force focus inside focus trap if it can', () => {
- return new Promise(resolve => {
- fixtureEl.innerHTML = [
- '<a href="#" id="outside">outside</a>',
- '<div id="focustrap" tabindex="-1">',
- ' <a href="#" id="inside">inside</a>',
- '</div>'
- ].join('')
-
- const trapElement = fixtureEl.querySelector('div')
- const focustrap = new FocusTrap({ trapElement })
- focustrap.activate()
-
- const inside = document.getElementById('inside')
-
- const focusInListener = () => {
- expect(spy).toHaveBeenCalled()
- document.removeEventListener('focusin', focusInListener)
- resolve()
- }
-
- const spy = spyOn(inside, 'focus')
- spyOn(SelectorEngine, 'focusableChildren').and.callFake(() => [inside])
-
- document.addEventListener('focusin', focusInListener)
-
- const focusInEvent = createEvent('focusin', { bubbles: true })
- Object.defineProperty(focusInEvent, 'target', {
- value: document.getElementById('outside')
- })
-
- document.dispatchEvent(focusInEvent)
- })
- })
-
- it('should wrap focus around forward on tab', () => {
- return new Promise(resolve => {
- fixtureEl.innerHTML = [
- '<a href="#" id="outside">outside</a>',
- '<div id="focustrap" tabindex="-1">',
- ' <a href="#" id="first">first</a>',
- ' <a href="#" id="inside">inside</a>',
- ' <a href="#" id="last">last</a>',
- '</div>'
- ].join('')
-
- const trapElement = fixtureEl.querySelector('div')
- const focustrap = new FocusTrap({ trapElement })
- focustrap.activate()
-
- const first = document.getElementById('first')
- const inside = document.getElementById('inside')
- const last = document.getElementById('last')
- const outside = document.getElementById('outside')
-
- spyOn(SelectorEngine, 'focusableChildren').and.callFake(() => [first, inside, last])
- const spy = spyOn(first, 'focus').and.callThrough()
-
- const focusInListener = () => {
- expect(spy).toHaveBeenCalled()
- first.removeEventListener('focusin', focusInListener)
- resolve()
- }
-
- first.addEventListener('focusin', focusInListener)
-
- const keydown = createEvent('keydown')
- keydown.key = 'Tab'
-
- document.dispatchEvent(keydown)
- outside.focus()
- })
- })
-
- it('should wrap focus around backwards on shift-tab', () => {
- return new Promise(resolve => {
- fixtureEl.innerHTML = [
- '<a href="#" id="outside">outside</a>',
- '<div id="focustrap" tabindex="-1">',
- ' <a href="#" id="first">first</a>',
- ' <a href="#" id="inside">inside</a>',
- ' <a href="#" id="last">last</a>',
- '</div>'
- ].join('')
-
- const trapElement = fixtureEl.querySelector('div')
- const focustrap = new FocusTrap({ trapElement })
- focustrap.activate()
-
- const first = document.getElementById('first')
- const inside = document.getElementById('inside')
- const last = document.getElementById('last')
- const outside = document.getElementById('outside')
-
- spyOn(SelectorEngine, 'focusableChildren').and.callFake(() => [first, inside, last])
- const spy = spyOn(last, 'focus').and.callThrough()
-
- const focusInListener = () => {
- expect(spy).toHaveBeenCalled()
- last.removeEventListener('focusin', focusInListener)
- resolve()
- }
-
- last.addEventListener('focusin', focusInListener)
-
- const keydown = createEvent('keydown')
- keydown.key = 'Tab'
- keydown.shiftKey = true
-
- document.dispatchEvent(keydown)
- outside.focus()
- })
- })
-
- it('should force focus on itself if there is no focusable content', () => {
- return new Promise(resolve => {
- fixtureEl.innerHTML = [
- '<a href="#" id="outside">outside</a>',
- '<div id="focustrap" tabindex="-1"></div>'
- ].join('')
-
- const trapElement = fixtureEl.querySelector('div')
- const focustrap = new FocusTrap({ trapElement })
- focustrap.activate()
-
- const focusInListener = () => {
- expect(spy).toHaveBeenCalled()
- document.removeEventListener('focusin', focusInListener)
- resolve()
- }
-
- const spy = spyOn(focustrap._config.trapElement, 'focus')
-
- document.addEventListener('focusin', focusInListener)
-
- const focusInEvent = createEvent('focusin', { bubbles: true })
- Object.defineProperty(focusInEvent, 'target', {
- value: document.getElementById('outside')
- })
-
- document.dispatchEvent(focusInEvent)
- })
- })
- })
-
- describe('deactivate', () => {
- it('should flag itself as no longer active', () => {
- const focustrap = new FocusTrap({ trapElement: fixtureEl })
- focustrap.activate()
- expect(focustrap._isActive).toBeTrue()
-
- focustrap.deactivate()
- expect(focustrap._isActive).toBeFalse()
- })
-
- it('should remove all event listeners', () => {
- const focustrap = new FocusTrap({ trapElement: fixtureEl })
- focustrap.activate()
-
- const spy = spyOn(EventHandler, 'off')
- focustrap.deactivate()
-
- expect(spy).toHaveBeenCalled()
- })
-
- it('doesn\'t try removing event listeners unless it needs to (in case it hasn\'t been activated)', () => {
- const focustrap = new FocusTrap({ trapElement: fixtureEl })
-
- const spy = spyOn(EventHandler, 'off')
- focustrap.deactivate()
-
- expect(spy).not.toHaveBeenCalled()
- })
- })
-})
+++ /dev/null
-import Manipulator from '../../../src/dom/manipulator.js'
-import ScrollBarHelper from '../../../src/util/scrollbar.js'
-import { clearBodyAndDocument, clearFixture, getFixture } from '../../helpers/fixture.js'
-
-describe('ScrollBar', () => {
- let fixtureEl
- const doc = document.documentElement
- const parseIntDecimal = arg => Number.parseInt(arg, 10)
- const getPaddingX = el => parseIntDecimal(window.getComputedStyle(el).paddingRight)
- const getMarginX = el => parseIntDecimal(window.getComputedStyle(el).marginRight)
- const getOverFlow = el => el.style.overflow
- const getPaddingAttr = el => Manipulator.getDataAttribute(el, 'padding-right')
- const getMarginAttr = el => Manipulator.getDataAttribute(el, 'margin-right')
- const getOverFlowAttr = el => Manipulator.getDataAttribute(el, 'overflow')
- const windowCalculations = () => {
- return {
- htmlClient: document.documentElement.clientWidth,
- htmlOffset: document.documentElement.offsetWidth,
- docClient: document.body.clientWidth,
- htmlBound: document.documentElement.getBoundingClientRect().width,
- bodyBound: document.body.getBoundingClientRect().width,
- window: window.innerWidth,
- width: Math.abs(window.innerWidth - document.documentElement.clientWidth)
- }
- }
-
- // iOS, Android devices and macOS browsers hide scrollbar by default and show it only while scrolling.
- // So the tests for scrollbar would fail
- const isScrollBarHidden = () => {
- const calc = windowCalculations()
- return calc.htmlClient === calc.htmlOffset && calc.htmlClient === calc.window
- }
-
- beforeAll(() => {
- fixtureEl = getFixture()
- // custom fixture to avoid extreme style values
- fixtureEl.removeAttribute('style')
- })
-
- afterAll(() => {
- fixtureEl.remove()
- })
-
- afterEach(() => {
- clearFixture()
- clearBodyAndDocument()
- })
-
- beforeEach(() => {
- clearBodyAndDocument()
- })
-
- describe('isBodyOverflowing', () => {
- it('should return true if body is overflowing', () => {
- document.documentElement.style.overflowY = 'scroll'
- document.body.style.overflowY = 'scroll'
- fixtureEl.innerHTML = '<div style="height: 110vh; width: 100%"></div>'
- const result = new ScrollBarHelper().isOverflowing()
-
- if (isScrollBarHidden()) {
- expect(result).toBeFalse()
- } else {
- expect(result).toBeTrue()
- }
- })
-
- it('should return false if body is not overflowing', () => {
- doc.style.overflowY = 'hidden'
- document.body.style.overflowY = 'hidden'
- fixtureEl.innerHTML = '<div style="height: 110vh; width: 100%"></div>'
- const scrollBar = new ScrollBarHelper()
- const result = scrollBar.isOverflowing()
-
- expect(result).toBeFalse()
- })
- })
-
- describe('getWidth', () => {
- it('should return an integer greater than zero, if body is overflowing', () => {
- doc.style.overflowY = 'scroll'
- document.body.style.overflowY = 'scroll'
- fixtureEl.innerHTML = '<div style="height: 110vh; width: 100%"></div>'
- const result = new ScrollBarHelper().getWidth()
-
- if (isScrollBarHidden()) {
- expect(result).toEqual(0)
- } else {
- expect(result).toBeGreaterThan(1)
- }
- })
-
- it('should return 0 if body is not overflowing', () => {
- document.documentElement.style.overflowY = 'hidden'
- document.body.style.overflowY = 'hidden'
- fixtureEl.innerHTML = '<div style="height: 110vh; width: 100%"></div>'
-
- const result = new ScrollBarHelper().getWidth()
-
- expect(result).toEqual(0)
- })
- })
-
- describe('hide - reset', () => {
- it('should adjust the inline padding of fixed elements which are full-width', () => {
- fixtureEl.innerHTML = [
- '<div style="height: 110vh; width: 100%">',
- ' <div class="fixed-top" id="fixed1" style="padding-right: 0px; width: 100vw"></div>',
- ' <div class="fixed-top" id="fixed2" style="padding-right: 5px; width: 100vw"></div>',
- '</div>'
- ].join('')
- doc.style.overflowY = 'scroll'
-
- const fixedEl = fixtureEl.querySelector('#fixed1')
- const fixedEl2 = fixtureEl.querySelector('#fixed2')
- const originalPadding = getPaddingX(fixedEl)
- const originalPadding2 = getPaddingX(fixedEl2)
- const scrollBar = new ScrollBarHelper()
- const expectedPadding = originalPadding + scrollBar.getWidth()
- const expectedPadding2 = originalPadding2 + scrollBar.getWidth()
-
- scrollBar.hide()
-
- let currentPadding = getPaddingX(fixedEl)
- let currentPadding2 = getPaddingX(fixedEl2)
- expect(getPaddingAttr(fixedEl)).toEqual(`${originalPadding}px`)
- expect(getPaddingAttr(fixedEl2)).toEqual(`${originalPadding2}px`)
- expect(currentPadding).toEqual(expectedPadding)
- expect(currentPadding2).toEqual(expectedPadding2)
-
- scrollBar.reset()
- currentPadding = getPaddingX(fixedEl)
- currentPadding2 = getPaddingX(fixedEl2)
- expect(getPaddingAttr(fixedEl)).toBeNull()
- expect(getPaddingAttr(fixedEl2)).toBeNull()
- expect(currentPadding).toEqual(originalPadding)
- expect(currentPadding2).toEqual(originalPadding2)
- })
-
- it('should remove padding & margin if not existed before adjustment', () => {
- fixtureEl.innerHTML = [
- '<div style="height: 110vh; width: 100%">',
- ' <div class="fixed" id="fixed" style="width: 100vw;"></div>',
- ' <div class="sticky-top" id="sticky" style=" width: 100vw;"></div>',
- '</div>'
- ].join('')
- doc.style.overflowY = 'scroll'
-
- const fixedEl = fixtureEl.querySelector('#fixed')
- const stickyEl = fixtureEl.querySelector('#sticky')
- const scrollBar = new ScrollBarHelper()
-
- scrollBar.hide()
- scrollBar.reset()
-
- expect(fixedEl.getAttribute('style').includes('padding-right')).toBeFalse()
- expect(stickyEl.getAttribute('style').includes('margin-right')).toBeFalse()
- })
-
- it('should adjust the inline margin and padding of sticky elements', () => {
- fixtureEl.innerHTML = [
- '<div style="height: 110vh">',
- ' <div class="sticky-top" style="margin-right: 10px; padding-right: 20px; width: 100vw; height: 10px"></div>',
- '</div>'
- ].join('')
- doc.style.overflowY = 'scroll'
-
- const stickyTopEl = fixtureEl.querySelector('.sticky-top')
- const originalMargin = getMarginX(stickyTopEl)
- const originalPadding = getPaddingX(stickyTopEl)
- const scrollBar = new ScrollBarHelper()
- const expectedMargin = originalMargin - scrollBar.getWidth()
- const expectedPadding = originalPadding + scrollBar.getWidth()
- scrollBar.hide()
-
- expect(getMarginAttr(stickyTopEl)).toEqual(`${originalMargin}px`)
- expect(getMarginX(stickyTopEl)).toEqual(expectedMargin)
- expect(getPaddingAttr(stickyTopEl)).toEqual(`${originalPadding}px`)
- expect(getPaddingX(stickyTopEl)).toEqual(expectedPadding)
-
- scrollBar.reset()
- expect(getMarginAttr(stickyTopEl)).toBeNull()
- expect(getMarginX(stickyTopEl)).toEqual(originalMargin)
- expect(getPaddingAttr(stickyTopEl)).toBeNull()
- expect(getPaddingX(stickyTopEl)).toEqual(originalPadding)
- })
-
- it('should not adjust the inline margin and padding of sticky and fixed elements when element do not have full width', () => {
- fixtureEl.innerHTML = '<div class="sticky-top" style="margin-right: 0px; padding-right: 0px; width: 50vw"></div>'
-
- const stickyTopEl = fixtureEl.querySelector('.sticky-top')
- const originalMargin = getMarginX(stickyTopEl)
- const originalPadding = getPaddingX(stickyTopEl)
-
- const scrollBar = new ScrollBarHelper()
- scrollBar.hide()
-
- const currentMargin = getMarginX(stickyTopEl)
- const currentPadding = getPaddingX(stickyTopEl)
-
- expect(currentMargin).toEqual(originalMargin)
- expect(currentPadding).toEqual(originalPadding)
-
- scrollBar.reset()
- })
-
- it('should not put data-attribute if element doesn\'t have the proper style property, should just remove style property if element didn\'t had one', () => {
- fixtureEl.innerHTML = [
- '<div style="height: 110vh; width: 100%">',
- ' <div class="sticky-top" id="sticky" style="width: 100vw"></div>',
- '</div>'
- ].join('')
-
- document.body.style.overflowY = 'scroll'
- const scrollBar = new ScrollBarHelper()
-
- const hasPaddingAttr = el => el.hasAttribute('data-bs-padding-right')
- const hasMarginAttr = el => el.hasAttribute('data-bs-margin-right')
- const stickyEl = fixtureEl.querySelector('#sticky')
- const originalPadding = getPaddingX(stickyEl)
- const originalMargin = getMarginX(stickyEl)
- const scrollBarWidth = scrollBar.getWidth()
-
- scrollBar.hide()
-
- expect(getPaddingX(stickyEl)).toEqual(scrollBarWidth + originalPadding)
- const expectedMargin = scrollBarWidth + originalMargin
- expect(getMarginX(stickyEl)).toEqual(expectedMargin === 0 ? expectedMargin : -expectedMargin)
- expect(hasMarginAttr(stickyEl)).toBeFalse() // We do not have to keep css margin
- expect(hasPaddingAttr(stickyEl)).toBeFalse() // We do not have to keep css padding
-
- scrollBar.reset()
-
- expect(getPaddingX(stickyEl)).toEqual(originalPadding)
- expect(getPaddingX(stickyEl)).toEqual(originalPadding)
- })
-
- describe('Body Handling', () => {
- it('should ignore other inline styles when trying to restore body defaults ', () => {
- document.body.style.color = 'red'
-
- const scrollBar = new ScrollBarHelper()
- const scrollBarWidth = scrollBar.getWidth()
- scrollBar.hide()
-
- expect(getPaddingX(document.body)).toEqual(scrollBarWidth)
- expect(document.body.style.color).toEqual('red')
-
- scrollBar.reset()
- })
-
- it('should hide scrollbar and reset it to its initial value', () => {
- const styleSheetPadding = '7px'
- fixtureEl.innerHTML = [
- '<style>',
- ' body {',
- ` padding-right: ${styleSheetPadding}`,
- ' }',
- '</style>'
- ].join('')
-
- const el = document.body
- const inlineStylePadding = '10px'
- el.style.paddingRight = inlineStylePadding
-
- const originalPadding = getPaddingX(el)
- expect(originalPadding).toEqual(parseIntDecimal(inlineStylePadding)) // Respect only the inline style as it has prevails this of css
- const originalOverFlow = 'auto'
- el.style.overflow = originalOverFlow
- const scrollBar = new ScrollBarHelper()
- const scrollBarWidth = scrollBar.getWidth()
-
- scrollBar.hide()
-
- const currentPadding = getPaddingX(el)
-
- expect(currentPadding).toEqual(scrollBarWidth + originalPadding)
- expect(currentPadding).toEqual(scrollBarWidth + parseIntDecimal(inlineStylePadding))
- expect(getPaddingAttr(el)).toEqual(inlineStylePadding)
- expect(getOverFlow(el)).toEqual('hidden')
- expect(getOverFlowAttr(el)).toEqual(originalOverFlow)
-
- scrollBar.reset()
-
- const currentPadding1 = getPaddingX(el)
- expect(currentPadding1).toEqual(originalPadding)
- expect(getPaddingAttr(el)).toBeNull()
- expect(getOverFlow(el)).toEqual(originalOverFlow)
- expect(getOverFlowAttr(el)).toBeNull()
- })
-
- it('should hide scrollbar and reset it to its initial value - respecting css rules', () => {
- const styleSheetPadding = '7px'
- fixtureEl.innerHTML = [
- '<style>',
- ' body {',
- ` padding-right: ${styleSheetPadding}`,
- ' }',
- '</style>'
- ].join('')
- const el = document.body
- const originalPadding = getPaddingX(el)
- const originalOverFlow = 'scroll'
- el.style.overflow = originalOverFlow
- const scrollBar = new ScrollBarHelper()
- const scrollBarWidth = scrollBar.getWidth()
-
- scrollBar.hide()
-
- const currentPadding = getPaddingX(el)
-
- expect(currentPadding).toEqual(scrollBarWidth + originalPadding)
- expect(currentPadding).toEqual(scrollBarWidth + parseIntDecimal(styleSheetPadding))
- expect(getPaddingAttr(el)).toBeNull() // We do not have to keep css padding
- expect(getOverFlow(el)).toEqual('hidden')
- expect(getOverFlowAttr(el)).toEqual(originalOverFlow)
-
- scrollBar.reset()
-
- const currentPadding1 = getPaddingX(el)
- expect(currentPadding1).toEqual(originalPadding)
- expect(getPaddingAttr(el)).toBeNull()
- expect(getOverFlow(el)).toEqual(originalOverFlow)
- expect(getOverFlowAttr(el)).toBeNull()
- })
-
- it('should not adjust the inline body padding when it does not overflow', () => {
- const originalPadding = getPaddingX(document.body)
- const scrollBar = new ScrollBarHelper()
-
- // Hide scrollbars to prevent the body overflowing
- doc.style.overflowY = 'hidden'
- doc.style.paddingRight = '0px'
-
- scrollBar.hide()
- const currentPadding = getPaddingX(document.body)
-
- expect(currentPadding).toEqual(originalPadding)
- scrollBar.reset()
- })
-
- it('should not adjust the inline body padding when it does not overflow, even on a scaled display', () => {
- const originalPadding = getPaddingX(document.body)
- const scrollBar = new ScrollBarHelper()
- // Remove body margins as would be done by Bootstrap css
- document.body.style.margin = '0'
-
- // Hide scrollbars to prevent the body overflowing
- doc.style.overflowY = 'hidden'
-
- // Simulate a discrepancy between exact, i.e. floating point body width, and rounded body width
- // as it can occur when zooming or scaling the display to something else than 100%
- doc.style.paddingRight = '.48px'
- scrollBar.hide()
-
- const currentPadding = getPaddingX(document.body)
-
- expect(currentPadding).toEqual(originalPadding)
-
- scrollBar.reset()
- })
- })
- })
-})