UNPKG

@epickris/bootstrap-kit

Version:

User interface and behaviour framework based on Bootstrap.

234 lines (179 loc) 6.36 kB
import { defineJQueryPlugin, getElementFromSelector, typeCheckConfig } from 'bootstrap/js/src/util'; import Data from 'bootstrap/js/src/dom/data'; import EventHandler from 'bootstrap/js/src/dom/event-handler'; import Manipulator from 'bootstrap/js/src/dom/manipulator'; import BaseComponent from 'bootstrap/js/src/base-component'; /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME = 'stage'; const DATA_KEY = 'bs.stage'; const EVENT_KEY = `.${DATA_KEY}`; const DATA_API_KEY = '.data-api'; const TRANSITION_END = 'transitionend'; const Default = { easing: 'cubic-bezier(.2, .7, .5, 1)', duration: 300, delay: 0, distance: 250, hiddenElements: '#sidebar' }; const DefaultType = { easing: 'string', duration: 'number', delay: 'number', distance: 'number', hiddenElements: 'string' }; const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`; const EVENT_KEYDOWN = `keydown${EVENT_KEY}`; const EVENT_OPEN = `open${EVENT_KEY}`; const EVENT_OPENED = `opened${EVENT_KEY}`; const EVENT_CLOSE = `close${EVENT_KEY}`; const EVENT_CLOSED = `closed${EVENT_KEY}`; const EVENT_CLICK = `click${EVENT_KEY}`; const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`; const CLASS_NAME_STAGE_OPEN = 'stage-open'; const CLASS_NAME_HIDDEN = 'hidden'; const SELECTOR_TOGGLE = '[data-toggle="stage"]'; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class Stage extends BaseComponent { constructor(element, config) { super(element); this._config = this._getConfig(config); } // Getters static get Default() { return Default; } static get DATA_KEY() { return DATA_KEY; } // Private _getConfig(config) { config = { ...Default, ...config }; typeCheckConfig(NAME, config, DefaultType); return config; } _isOpen() { return this._element.classList.contains(CLASS_NAME_STAGE_OPEN); } _complete() { document.body.style.overflow = 'auto'; if ('ontouchstart' in document.documentElement) { EventHandler.off(document, EVENT_TOUCHMOVE); } this._config.hiddenElements.classList.add(CLASS_NAME_HIDDEN); this._element.classList.remove(CLASS_NAME_STAGE_OPEN); this._element.style.transition = ''; this._element.style.transform = ''; this._element.style['-webkit-transition'] = this._element.style.transition; this._element.style['-webkit-transform'] = this._element.style.transform; this._element.style['-ms-transition'] = this._element.style.transition; this._element.style['-ms-transform'] = this._element.style.transform; EventHandler.trigger(this._element, EVENT_CLOSED); } // Public toggle() { if (this._isOpen()) { this.close(); } else { this.open(); } } open() { document.body.style.overflow = 'hidden'; if ('ontouchstart' in document.documentElement) { EventHandler.on(document, EVENT_TOUCHMOVE, event => { event.preventDefault(); }); } this._config.hiddenElements.classList.remove(CLASS_NAME_HIDDEN); EventHandler.one(window, EVENT_KEYDOWN, event => { event.which = 27 && this.close(); }); EventHandler.on(this._element, EVENT_CLICK, this.close.bind(this)); EventHandler.trigger(this._element, EVENT_OPEN); this._element.classList.add(CLASS_NAME_STAGE_OPEN); this._element.style.transition = `transform ${this._config.duration}ms ${this._config.easing}`; this._element.style['-webkit-transition'] = `-webkit-${this._element.style.transition}`; this._element.style['-ms-transition'] = `-ms-${this._element.style.transition}`; // eslint-disable-next-line no-unused-expressions this._element.scrollWidth; // Force reflow this._element.style.transform = `translateX(${this._config.distance}px)`; this._element.style['-webkit-transform'] = `-webkit-${this._element.style.transform}`; this._element.style['-ms-transform'] = `-ms-${this._element.style.transform}`; EventHandler.one(this._element, TRANSITION_END, () => { EventHandler.trigger(this._element, EVENT_OPENED); }); EventHandler.emulateTransitionEnd(this._element, this._config.duration); } close() { EventHandler.off(window, EVENT_KEYDOWN); EventHandler.trigger(this._element, EVENT_CLOSE); EventHandler.off(this._element, EVENT_CLICK); this._element.style.transform = 'none'; this._element.style['-webkit-transform'] = this._element.style.transform; this._element.style['-ms-transform'] = this._element.style.transform; EventHandler.one(this._element, TRANSITION_END, this._complete.bind(this)); EventHandler.emulateTransitionEnd(this._element, this._config.duration); } // Static static stageInterface(element, config) { let data = Data.get(element, DATA_KEY); let _config = { ...Default, ...Manipulator.getDataAttributes(element) }; if (typeof config === 'object') { _config = { ..._config, ...config }; } if (!data) { data = new Stage(element, _config); } if (typeof config === 'string') { if (typeof data[config] === 'undefined') { throw new TypeError(`No method named "${config}"`); } data[config](); } } static jQueryInterface(config) { return this.each(function () { Stage.stageInterface(this, config); }); } static dataApiClickHandler() { const target = getElementFromSelector(this); if (!target) { return; } Stage.stageInterface(target, 'toggle'); } } /** * ------------------------------------------------------------------------ * Data Api implementation * ------------------------------------------------------------------------ */ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_TOGGLE, Stage.dataApiClickHandler); /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .Carousel to jQuery only if jQuery is present */ defineJQueryPlugin(NAME, Stage); export default Stage;