UNPKG

web-ui-pack

Version:
441 lines (440 loc) 16.7 kB
import WUPBaseElement from "./baseElement"; import { px2Number, styleTransform } from "./helpers/styleHelpers"; import { getOffset } from "./popup/popupPlacements"; const tagName = "wup-spin"; export default class WUPSpinElement extends WUPBaseElement { #ctr = this.constructor; static get $styleRoot() { return `:root { --spin-1: #ffa500; --spin-2: #fff; --spin-t: 1.2s; --spin-size: 3em; --spin-item-size: calc(var(--spin-size) / 8); --spin-fade: rgba(255,255,255,0.43); }`; } static get $styleApplied() { return ""; } static get $style() { return `${super.$style} @keyframes WUP-SPIN-1 { 100% { transform: rotate(360deg); } } :host { contain: style; z-index: 100; width: var(--spin-size); height: var(--spin-size); top:0; left:0; pointer-events: none; } :host, :host>div { display: inline-block; box-sizing: border-box; border-radius: 50%; } :host>div { animation: WUP-SPIN-1 var(--spin-t) linear infinite; width: 100%; height: 100%; left:0; top:0; } :host>div[fade] { display: block; position: absolute; left:0; top:0; animation: none; border: none; border-radius: var(--border-radius); transform: none; z-index: -1; background: var(--spin-fade); } :host>div[fade]:after { content: none; } ${this.$styleApplied}`; } static get mappedAttributes() { const m = super.mappedAttributes; m.fit.type = 0; m.overflowtarget.type = 6; return m; } static $defaults = { overflowOffset: [4, 4], overflowFade: true, overflowTarget: "auto", inline: false, fit: "auto", }; static cloneDefaults() { const d = super.cloneDefaults(); d.overflowOffset = [...d.overflowOffset]; return d; } static _itemsCount = 1; $refresh() { this.gotChanges([]); } connectedCallback() { this.style.display = "none"; super.connectedCallback(); } gotRemoved() { super.gotRemoved(); this.#frameId && window.cancelAnimationFrame(this.#frameId); this.#frameId = undefined; if (this.#prevTarget?.isConnected) { this.#prevTarget.removeAttribute("aria-busy"); this.#prevTarget = undefined; } } gotRender() { for (let i = 0; i < this.#ctr._itemsCount; ++i) { this.appendChild(document.createElement("div")); } } gotReady() { this.setAttribute("aria-label", "Loading. Please wait"); super.gotReady(); } #prevTarget; $refFade; gotChanges(propsChanged) { super.gotChanges(propsChanged); this.style.cssText = ""; this.#prevRect = undefined; this.#frameId && window.cancelAnimationFrame(this.#frameId); this.#frameId = undefined; const nextTarget = this.target; if (this.#prevTarget !== nextTarget) { this.#prevTarget?.removeAttribute("aria-busy"); nextTarget.setAttribute("aria-busy", true); this.#prevTarget = nextTarget; } if (!this._opts.inline) { if (this._opts.overflowFade && !this.$refFade) { this.$refFade = this.appendChild(document.createElement("div")); this.$refFade.setAttribute("fade", ""); const s = getComputedStyle(this.target); this.$refFade.style.borderTopLeftRadius = s.borderTopLeftRadius; this.$refFade.style.borderTopRightRadius = s.borderTopRightRadius; this.$refFade.style.borderBottomLeftRadius = s.borderBottomLeftRadius; this.$refFade.style.borderBottomRightRadius = s.borderBottomRightRadius; } else if (!this._opts.overflowFade && this.$refFade) { this.$refFade.remove(); this.$refFade = undefined; } this.style.position = "absolute"; const goUpdate = () => { this.#prevRect = this.updatePosition(); this.#frameId = window.requestAnimationFrame(goUpdate); }; goUpdate(); } else { this.style.transform = ""; this.style.position = ""; this.$refFade?.remove(); this.$refFade = undefined; if (this.isFitParent) { const goUpdate = () => { this.style.display = "none"; const p = this.parentElement; const r = { width: p.clientWidth, height: p.clientHeight, left: 0, top: 0 }; this.style.display = ""; if (this.#prevRect && this.#prevRect.width === r.width && this.#prevRect.height === r.height) { return; } this.style.cssText = ""; const ps = getComputedStyle(p); const { paddingTop, paddingLeft, paddingBottom, paddingRight } = ps; const innW = r.width - px2Number(paddingLeft) - px2Number(paddingRight); const innH = r.height - px2Number(paddingTop) - px2Number(paddingBottom); let sz = Math.min(innH, innW); sz -= sz % 2; const varItemSize = ps.getPropertyValue("--spin-item-size"); const scale = Math.min(sz / this.clientWidth, 1); this.style.cssText = `--spin-size: ${sz}px; --spin-item-size: calc(${varItemSize} * ${scale})`; this.#prevRect = r; this.#frameId = window.requestAnimationFrame(goUpdate); }; goUpdate(); } } } get isFitParent() { const o = this._opts.fit; return o === "auto" ? !this._opts.inline : o; } get target() { const trg = this._opts.overflowTarget; return this._opts.inline || trg === "auto" || !trg ? this.parentElement : trg; } get hasRelativeParent() { const p = this.offsetParent; return !!p && getComputedStyle(p).position === "relative"; } #prevRect; #frameId; updatePosition() { const trg = this.target; if (!trg.clientWidth || !trg.clientHeight) { this.style.display = "none"; return undefined; } this.style.display = ""; const r = { width: trg.offsetWidth, height: trg.offsetHeight, left: trg.offsetLeft, top: trg.offsetTop }; if (this.offsetParent === trg) { r.top = 0; r.left = 0; } else if (!this.hasRelativeParent) { const { top, left } = trg.getBoundingClientRect(); r.top = top; r.left = left; } if (this.#prevRect && this.#prevRect.top === r.top && this.#prevRect.left === r.left && this.#prevRect.width === r.width && this.#prevRect.height === r.height) { return this.#prevRect; } const offset = getOffset(this._opts.overflowOffset); this.style.display = ""; const w = r.width - offset.left - offset.right; const h = r.height - offset.top - offset.bottom; const scale = this.isFitParent ? Math.min(Math.min(h, w) / this.clientWidth, 1) : 1; const left = Math.round(r.left + offset.left + (w - this.clientWidth) / 2); const top = Math.round(r.top + offset.top + (h - this.clientHeight) / 2); styleTransform(this, "translate", `${left}px,${top}px`); styleTransform(this, "scale", scale === 1 ? "" : `${scale}`); if (this.$refFade) { styleTransform(this.$refFade, "translate", `${r.left - left}px,${r.top - top}px`); styleTransform(this.$refFade, "scale", scale === 1 || !scale ? "" : `${1 / scale}`); this.$refFade.style.width = `${r.width}px`; this.$refFade.style.height = `${r.height}px`; } return r; } } spinUseRing(WUPSpinElement); customElements.define(tagName, WUPSpinElement); export function spinSetStyle(cls, itemsCount, getter) { cls._itemsCount = itemsCount; Object.defineProperty(cls, "$styleApplied", { configurable: true, get: getter, }); } export function spinUseRing(cls) { spinSetStyle(cls, 1, () => `:host>div { border: var(--spin-item-size) solid var(--spin-1); border-top-color: var(--spin-2); }`); } export function spinUseDualRing(cls) { spinSetStyle(cls, 1, () => `:root { --spin-2: transparent; } :host>div { border: var(--spin-item-size) solid; border-color: var(--spin-2) var(--spin-1) var(--spin-2) var(--spin-1); }`); } export function spinUseTwinDualRing(cls) { spinSetStyle(cls, 2, () => `@keyframes WUP-SPIN-2-2 { 0% { transform: translate(-50%, -50%) rotate(360deg); } 100% { transform: translate(-50%, -50%) rotate(0deg); } } :root { --spin-2: #b35e03; --spin-item-size: max(1px, calc(var(--spin-size) / 12)); } :host { position: relative; } :host>div:nth-child(1) { border: var(--spin-item-size) solid; border-color: transparent var(--spin-1) transparent var(--spin-1); } :host>div:nth-child(2) { border: var(--spin-item-size) solid; border-color: var(--spin-2) transparent var(--spin-2) transparent; position: absolute; width: calc(100% - var(--spin-item-size) * 3); height: calc(100% - var(--spin-item-size) * 3); left: 50%; top: 50%; transform: translate(-50%,-50%); animation: WUP-SPIN-2-2 var(--spin-t) linear infinite; }`); } export function spinUseRoller(cls) { const cnt = 4; spinSetStyle(cls, cnt, () => { let s = ""; for (let i = 1; i <= cnt - 1; ++i) { s += `:host>div:nth-child(${i}) { animation-delay: -0.${15 * (cnt - i)}s } `; } return `:host { position: relative; } :host>div { animation-timing-function: cubic-bezier(0.5, 0, 0.5, 1); position: absolute; border: var(--spin-item-size) solid; border-color: var(--spin-1) transparent transparent transparent; } ${s}`; }); } export function spinUseDotRoller(cls) { const cnt = 7; spinSetStyle(cls, cnt, () => { let s = ""; for (let i = 1; i <= cnt; ++i) { s += `:host>div:nth-child(${i}) { animation-delay: -${0.036 * i}s; } :host>div:nth-child(${i}):after { transform: rotate(calc(45deg + var(--spin-step) * ${i - 1})); } `; } return `:root { --spin-step: 24deg; } :host { position: relative; } :host>div { animation-timing-function: cubic-bezier(0.5, 0, 0.5, 1); position: absolute; } :host>div:after { content: " "; display: block; position: absolute; left: 0; top: calc(50% - var(--spin-item-size) / 2); transform-origin: calc(var(--spin-size) / 2); width: var(--spin-item-size); height: var(--spin-item-size); border-radius: 50%; background: var(--spin-1); } ${s}`; }); } export function spinUseDotRing(cls) { const cnt = 10; spinSetStyle(cls, cnt, () => { let s = ""; for (let i = 1; i <= cnt; ++i) { s += `:host>div:nth-child(${i}):after { animation-delay: ${0.1 * (i - 1)}s; } :host>div:nth-child(${i}) { transform: translate(-50%,-50%) rotate(${(360 / cnt) * (i - 1)}deg) } `; } return `@keyframes WUP-SPIN-2 { 0%,20%,80%,100% { transform: scale(1); background: var(--spin-1) } 50% { transform: scale(1.4); background: var(--spin-2) } } :root { --spin-2: #ff5200; } :host { position: relative; } :host>div { position: absolute; width: calc(100% / 1.4142135623730951); height: calc(100% / 1.4142135623730951); animation: none; top:50%; left:50%; } :host>div:after { animation: WUP-SPIN-2 var(--spin-t) linear infinite; content: " "; display: block; width: var(--spin-item-size); height: var(--spin-item-size); border-radius: 50%; background: var(--spin-1); } ${s}`; }); } export function spinUseSpliceRing(cls) { const cnt = 12; spinSetStyle(cls, cnt, () => { let s = ""; for (let i = 1; i <= cnt; ++i) { s += `:host>div:nth-child(${i}) { animation-delay: -${0.1 * (cnt - i)}s; transform: rotate(${(360 / cnt) * (i - 1)}deg); } `; } return `@keyframes WUP-SPIN-3 { 100% { opacity: 0; background: var(--spin-2); } } :root { --spin-item-size: calc(var(--spin-size) / 10); } :host { position: relative; } :host>div { animation: WUP-SPIN-3 var(--spin-t) linear infinite; position: absolute; width: calc(var(--spin-size) / 4); height: var(--spin-item-size); left: 0; top: calc(50% - var(--spin-item-size) / 2); transform-origin: calc(var(--spin-size) / 2); background: var(--spin-1); border-radius: calc(var(--spin-item-size) / 2); } ${s}`; }); } export function spinUseHash(cls) { spinSetStyle(cls, 2, () => `@keyframes WUP-SPIN-4-1 { 0% { width: var(--spin-item-size); box-shadow: var(--spin-1) var(--spin-end) var(--spin-pad2), var(--spin-1) var(--spin-start) var(--spin-pad); } 35% { width: var(--spin-size); box-shadow: var(--spin-1) 0 var(--spin-pad2), var(--spin-1) 0 var(--spin-pad); } 70% { width: var(--spin-item-size); box-shadow: var(--spin-1) var(--spin-start) var(--spin-pad2), var(--spin-1) var(--spin-end) var(--spin-pad); } 100% { box-shadow: var(--spin-1) var(--spin-end) var(--spin-pad2), var(--spin-1) var(--spin-start) var(--spin-pad); } } @keyframes WUP-SPIN-4-2 { 0% { height: var(--spin-item-size); box-shadow: var(--spin-2) var(--spin-pad) var(--spin-end), var(--spin-2) var(--spin-pad2) var(--spin-start); } 35% { height: var(--spin-size); box-shadow: var(--spin-2) var(--spin-pad) 0, var(--spin-2) var(--spin-pad2) 0; } 70% { height: var(--spin-item-size); box-shadow: var(--spin-2) var(--spin-pad) var(--spin-start), var(--spin-2) var(--spin-pad2) var(--spin-end); } 100% { box-shadow: var(--spin-2) var(--spin-pad) var(--spin-end), var(--spin-2) var(--spin-pad2) var(--spin-start); } } :root { --spin-2: #b35e03; --spin-item-size: calc(var(--spin-size) / 8); --spin-end: calc((var(--spin-size) - var(--spin-item-size)) / 2); --spin-start: calc((var(--spin-end)) * -1); --spin-pad: calc(var(--spin-size) / 2 - var(--spin-size) / 3 + var(--spin-item-size) / 3); --spin-pad2: calc(-1 * var(--spin-pad)); } :host { position: relative; padding: 3px; } :host>div { position: absolute; transform: translate(-50%, -50%) rotate(165deg); top:50%; left:50%; width: var(--spin-item-size); height: var(--spin-item-size); border-radius: calc(var(--spin-item-size) / 2); } :host>div:nth-child(1) { animation: var(--spin-t) ease 0s infinite normal none running WUP-SPIN-4-1; } :host>div:nth-child(2) { animation: var(--spin-t) ease 0s infinite normal none running WUP-SPIN-4-2; }`); }