web-ui-pack
Version:
Web package with UI elements
441 lines (440 loc) • 16.7 kB
JavaScript
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}
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, () => ` 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 ` 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 ` 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, () => ` 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); }
}
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;
}`);
}