@mdbootstrap/bootstrap-dark-mode
Version:
Responsive Dark Mode theme built with Bootstrap 5 with Dark Mode toggle button that switches between dark and light themes.
106 lines (84 loc) • 2.63 kB
JavaScript
import SelectorEngine from '../dom/selector-engine';
import { isVisible, typeCheckConfig } from './index';
const NAME = 'Stack';
const DEFAULT_OPTIONS = {
position: 'top',
container: null,
refresh: 1000,
filter: (el) => {
return el;
},
};
const TYPE_OPTIONS = {
position: 'string',
container: '(undefined|null|string)',
refresh: 'number',
filter: 'function',
};
class Stack {
constructor(element, selector, options) {
this._element = element;
this._selector = selector;
this._options = this._getConfig(options);
this._offset = null;
if (this._options.container) {
this._parent = SelectorEngine.findOne(this._options.container);
}
}
get stackableElements() {
return SelectorEngine.find(this._selector)
.filter((el, i) => this._options.filter(el, i))
.map((el) => ({ el, rect: el.getBoundingClientRect() }))
.filter(({ el, rect }) => {
const basicCondition = el !== this._element && isVisible(el);
if (this._offset === null) {
return basicCondition;
}
return basicCondition && this._getBoundryOffset(rect) < this._offset;
})
.sort((a, b) => {
return this._getBoundryOffset(b.rect) - this._getBoundryOffset(a.rect);
});
}
get nextElements() {
return SelectorEngine.find(this._selector)
.filter((el) => el !== this._element)
.filter((el, i) => this._options.filter(el, i))
.filter((el) => {
this._offset = null;
return this._getBoundryOffset(el.getBoundingClientRect()) > this._offset;
});
}
_getConfig(options) {
const config = {
...DEFAULT_OPTIONS,
...options,
};
typeCheckConfig(NAME, config, TYPE_OPTIONS);
return config;
}
_getBoundryOffset(rect) {
const { position } = this._options;
let parentTopOffset = 0;
let parentBottomBoundry = window.innerHeight;
if (this._parent) {
const parentRect = this._parent.getBoundingClientRect();
parentTopOffset = parentRect.top;
parentBottomBoundry = parentRect.bottom;
}
if (position === 'top') {
return rect.top - parentTopOffset;
}
return parentBottomBoundry - rect.bottom;
}
calculateOffset() {
const [previousElement] = this.stackableElements;
if (!previousElement) {
this._offset = 0;
} else {
this._offset = this._getBoundryOffset(previousElement.rect) + previousElement.rect.height;
}
return this._offset;
}
}
export default Stack;