UNPKG

@scidian/osui

Version:

Lightweight JavaScript UI library.

111 lines (90 loc) 4.2 kB
import { Element } from '../core/Element.js'; import { Popper } from '../utils/Popper.js'; import { ALIGN, OVERFLOW, POSITION } from '../utils/Popper.js'; class Button extends Element { constructor(buttonText) { super(document.createElement('button')); const self = this; this.setClass('osui-button'); this.dom.textContent = buttonText ?? ' '; this.attachedMenu = undefined; this.menuOffsetX = 0; this.menuOffsetY = 0; this.alignMenu = ALIGN.LEFT; this.overflowMenu = OVERFLOW.RIGHT; Object.defineProperty(this, 'disabled', { get: function() { return (this.dom) ? this.dom.disabled : true; }, set: function(isDisabled) { if (this.dom) this.dom.disabled = isDisabled; } }); /***** EVENTS *****/ function onPointerDown(event) { // Hide Tooltip const hideEvent = new Event('hidetooltip', { bubbles: true }); self.dom.dispatchEvent(hideEvent); } this.dom.addEventListener('pointerdown', onPointerDown); this.dom.addEventListener('destroy', function() { self.dom.removeEventListener('pointerdown', onPointerDown); if (self.attachedMenu) self.detachMenu(); }, { once: true }); } /** Attaches a PopUp menu to Button */ attachMenu(osuiMenu, popupStyle = false) { const self = this; if (popupStyle) osuiMenu.addClass('osui-popup-menu'); // Button Click function buttonPointerDown(event) { event.stopPropagation(); event.preventDefault(); // Pop Menu if (self.hasClass('osui-selected') === false) { self.addClass('osui-selected'); // Update position popMenu(); // Apply class to show menu, CSS will handle the transition setTimeout(() => { if (!self.dom) return; osuiMenu.showMenu(self.dom, true /* giveFocus? */); }, 0); } // Let other menus know click occured document.dispatchEvent(new Event('closemenu')); } // Pop Menu (internally calculates proper positioning) function popMenu() { const popped = Popper.popUnder(osuiMenu.dom, self.dom, self.alignMenu, self.menuOffsetX, self.menuOffsetY, self.overflowMenu); osuiMenu.removeClass('osui-slide-up'); osuiMenu.removeClass('osui-slide-down'); osuiMenu.addClass((popped === POSITION.UNDER) ? 'osui-slide-down' : 'osui-slide-up'); } // Verify element is a 'osui-menu', apply 'osui-menu-button' class, store for later if (osuiMenu.hasClass('osui-menu') === false) return this; this.addClass('osui-menu-button'); this.attachedMenu = osuiMenu; // Add menu to document, add event handler document.body.appendChild(osuiMenu.dom); this.dom.addEventListener('pointerdown', buttonPointerDown); // Observer: Calls popMenu when button is initially added to the DOM. This is done to decide initial // (over / under) popper placement, then the observer is removed. const observer = new MutationObserver((mutations, observer) => { if (document.contains(this.dom)) { popMenu(); observer.disconnect(); } }); observer.observe(document, { attributes: false, childList: true, characterData: false, subtree: true }); // Handle document resize / positioning window.addEventListener('resize', popMenu); /** Removes attached menu */ this.detachMenu = function() { if (self.hasClass('osui-menu-button') === false) return; self.removeClass('osui-menu-button'); window.removeEventListener('resize', popMenu); self.dom.removeEventListener('pointerdown', buttonPointerDown); self.attachedMenu.destroy(); document.body.removeChild(self.attachedMenu.dom); self.attachedMenu = undefined; }; } } export { Button };