UNPKG

web-ui-pack

Version:
302 lines (301 loc) 10.1 kB
import WUPBaseModal from "./baseModal"; import { px2Number } from "./helpers/styleHelpers"; export var NotifyOpenCases; (function (NotifyOpenCases) { NotifyOpenCases[NotifyOpenCases["onManualCall"] = 0] = "onManualCall"; NotifyOpenCases[NotifyOpenCases["onInit"] = 1] = "onInit"; })(NotifyOpenCases || (NotifyOpenCases = {})); export var NotifyCloseCases; (function (NotifyCloseCases) { NotifyCloseCases[NotifyCloseCases["onManualCall"] = 0] = "onManualCall"; NotifyCloseCases[NotifyCloseCases["onCloseClick"] = 1] = "onCloseClick"; NotifyCloseCases[NotifyCloseCases["onTimeEnd"] = 2] = "onTimeEnd"; })(NotifyCloseCases || (NotifyCloseCases = {})); const tagName = "wup-notify"; export default class WUPNotifyElement extends WUPBaseModal { #ctr = this.constructor; static get observedOptions() { return ["autoClose", "closeOnClick", "openCase", "placement", "selfRemove"]; } static get observedAttributes() { return super.observedAttributes; } static get $styleRoot() { return `:root { --notify-anim-t: 400ms; --notify-margin: 1em 0; --notify-w: 300px; --notify-text: #fff; --notify-bg: rgba(16,70,82,0.9); --notify-shadow: #0003; --notify-progress: #009fbc; } [wupdark] { --notify-text: #d8d8d8; --notify-bg: rgba(16,70,82,0.9); --notify-shadow: #0006; }`; } static get $style() { return `${super.$style} :host { --modal-anim: var(--notify-anim-t) cubic-bezier(0,0,0.2,1) 0ms; z-index: 9010; min-height: 64px; max-height: 80vh; width: var(--notify-w); max-width: 80wv; margin: var(--notify-margin); color: var(--notify-text); background: var(--notify-bg); box-shadow: 0 1px 4px 0 var(--notify-shadow); } :host[w-placement=top-left], :host[w-placement=bottom-left] { border-radius: 0 var(--border-radius) var(--border-radius) 0; left: 0; transform: translateX(-100%); } :host[w-placement=top-right], :host[w-placement=bottom-right] { border-radius: var(--border-radius) 0 0 var(--border-radius); right: 0; transform: translateX(100%); } :host[w-placement=top-middle], :host[w-placement="bottom-middle"] { margin-left: auto; margin-right: auto; left:0; right:0; transform: translateY(-100%); } :host[w-placement=top-left], :host[w-placement=top-middle], :host[w-placement=top-right] { top:0; } :host[w-placement=bottom-left], :host[w-placement=bottom-middle], :host[w-placement=bottom-right] { bottom:0; } :host[show] { transform: none; } :host > button[close] { --icon-img: var(--wup-icon-cross); --icon: var(--notify-text); z-index: 10; position: absolute; right:0; top:0; margin: 0.4em; } :host > [progress] { position: absolute; bottom:0; left:0; width: 100%; height: 5px; background: var(--notify-progress); transform-origin: left; } `; } static $defaults = { openCase: 1, placement: "bottom-left", autoClose: 5000, closeOnClick: false, selfRemove: true, pauseOnHover: true, pauseOnWinBlur: true, }; static $show(opts) { const me = document.createElement(tagName); opts.className && me.classList.add(opts.className); me.$options.selfRemove = true; Object.assign(me.$options, opts.defaults); me.$options.openCase = 1; me.textContent = opts.textContent; document.body.appendChild(me); opts.onRender?.(me); return me; } $refClose; $refProgress; $isPaused = false; $pause() { this.#isPlayed = false; return this.#pauseRef?.pause() ?? -1; } #pauseRef; #isPlayed = false; get $isPlayed() { return this.#isPlayed; } $play(ms) { if (!ms) { ms = this.#pauseRef?.leftPlayTime ?? (this._opts.autoClose || 0); } this.#isPlayed = true; const now = Date.now(); const t1 = setTimeout(() => { this.goClose(2, null); }, ms); const anim = this.#pauseRef?.anim ?? this.$refProgress.animate([{ transform: "scaleX(100%)" }, { transform: "scaleX(0)" }], { fill: "forwards", duration: ms - 100, }); anim.play(); const msConst = ms; this.#pauseRef = { anim, pause: () => { clearTimeout(t1); anim.pause(); const left = msConst - Date.now() + now; this.#pauseRef.leftPlayTime = left; return left; }, }; } gotRender(isOpening = false) { if (!isOpening) { return; } this.setAttribute("role", "alert"); this.setAttribute("w-placement", this._opts.placement); if (!this.$refClose) { this.$refClose = document.createElement("button"); const q = this.$refClose; q.type = "button"; q.setAttribute("aria-label", __wupln("close", "aria")); q.setAttribute(this.#ctr.classNameBtnIcon, ""); q.setAttribute("close", ""); this.prepend(q); q.onclick = (e) => this.goClose(1, e); } if (!this.$refProgress && this._opts.autoClose) { this.$refProgress = document.createElement("div"); const q = this.$refProgress; q.setAttribute("progress", ""); q.setAttribute("role", "progressbar"); this.appendChild(q); } } gotChanges(propsChanged) { super.gotChanges(propsChanged); this._opts.openCase === 1 && this.goOpen(1, null); } _dy = 0; _dx = ""; gotOpen(openCase, e) { this.gotRender(true); this._opts.closeOnClick && this.appendEvent(this, "click", (ev) => this.gotClick(ev)); const curNum = this._openedItems.push(this); if (curNum > 1) { this._dx = getComputedStyle(this).transform; const lastI = curNum - 2; const prev = this._openedItems.findLast((a, i) => i <= lastI && this.isSameSibling(a)); if (prev) { this.style.transition = "none"; this.refreshVertical([prev, this], true); const savedState = this.style.transform; this.style.transform = `${this._dx} translateY(${this._dy}px)`; setTimeout(() => { this.style.transition = ""; this.style.transform = savedState; }); } } const ms = this._opts.autoClose; if (ms) { let allowByFocus = true; if (this._opts.pauseOnWinBlur) { this.appendEvent(window, "blur", () => this.$pause()); this.appendEvent(window, "focus", () => this.$play()); allowByFocus = document.hasFocus(); } allowByFocus && this.$play(ms); if (this._opts.pauseOnHover) { this.appendEvent(this, "mouseenter", () => { const left = this.$pause(); this.appendEvent(this, "mouseleave", () => this.$play(left), { once: true }); }); this.appendEvent(this, "touchstart", () => { this.$isPlayed ? this.$pause() : this.$play(); }); } } } isSameSibling(item) { return item._opts.placement === this._opts.placement && item.offsetHeight > 0; } refreshVertical(items, isInit = false) { let isBottom = false; switch (this._opts.placement) { case "bottom-left": case "bottom-middle": case "bottom-right": isBottom = true; break; default: break; } let prev; if (!items) items = this._openedItems.filter((x) => this.isSameSibling(x)); const { marginBottom, marginTop } = getComputedStyle(this); items.forEach((a) => { const isNext = !!prev; if (isNext) { const height = prev.offsetHeight; a._dy = Math.round(isBottom ? prev._dy - height - px2Number(marginBottom) : prev._dy + height + px2Number(marginTop)); a.style.transform = `translateY(${a._dy}px)`; } else if (!isInit) { a.style.transform = ""; a._dy = 0; } prev = a; }); } gotClose(closeCase, ev) { this.style.transform = this._dx ? `${this._dx} translateY(${this._dy}px)` : ""; this.disposeEvents(); } resetState() { super.resetState(); this.style.transform = ""; const i = this._openedItems.indexOf(this); if (i > -1) { this._openedItems.splice(i, 1); this.refreshVertical(); } this.isConnected && this._opts.selfRemove && this.remove(); } gotClick(e) { const t = e.target; if (e.defaultPrevented || (t === this && !this._opts.closeOnClick) || e.button) { return; } if (this._opts.closeOnClick) { this.goClose(1, e); return; } const all = this.querySelectorAll("[close]").values(); for (const el of all) { if (this.itsMe.call(el, t)) { this.goClose(1, e); return; } } } get _openedItems() { return __openedItems; } } const __openedItems = []; customElements.define(tagName, WUPNotifyElement);