arlet-loadding
Version:
Un componente de indicador de carga con múltiples animaciones personalizables.
534 lines (408 loc) • 17.3 kB
JavaScript
class ArletLoadding {
constructor(container) {
this.container = container;
this.loadding = null;
}
show({
texto = 'Cargando...',
tipo = 'zigzag-lines',
}) {
this.cerrar();
this.loadding = document.createElement('div');
this.loadding.classList.add('arlet-loaddign');
const normalizedTipo = typeof tipo === 'string' ? tipo.trim() : '';
const lowerTipo = normalizedTipo.toLowerCase();
const typeKey = lowerTipo.endsWith('-type') ? lowerTipo.slice(0, -5) : lowerTipo;
const imageConfig = this._parseImageTipo(normalizedTipo);
const spin = document.createElement('div');
spin.classList.add('spin');
const isImageTipo = Boolean(imageConfig);
if (!isImageTipo && normalizedTipo) {
const typeClass = normalizedTipo.endsWith('-type') ? normalizedTipo : `${normalizedTipo}-type`;
this.loadding.classList.add(typeClass);
}
if (isImageTipo) {
this._buildImageSpin({ spin, imageConfig, texto });
} else if (typeKey === 'ia') {
this._buildIaSpin({ spin });
} else if (typeKey === 'robot') {
this._buildRobotSpin({ spin });
} else if (typeKey === 'bike') {
this._buildBikeSpin({ spin });
} else if (typeKey === 'motor-bike') {
this._buildMotorBikeSpin({ spin });
} else if (typeKey === 'weaves') {
this._buildWeavesSpin({ spin });
} else if (typeKey === 'glass-ring') {
this._buildGlassRingSpin({ spin });
} else if (typeKey === 'gradient-bar') {
this._buildGradientBarSpin({ spin });
} else if (typeKey === 'dual-pulse') {
this._buildDualPulseSpin({ spin });
} else if (typeKey === 'line-wave') {
this._buildLineWaveSpin({ spin });
} else {
const spinCenter = document.createElement('div');
spinCenter.classList.add('spin-center');
for (let i = 0; i < 5; i += 1) {
const circle = document.createElement('div');
circle.classList.add('spin-center__circle');
spinCenter.appendChild(circle);
}
spin.appendChild(spinCenter);
}
const textWrapper = document.createElement('p');
textWrapper.classList.add('text_arlet-loadding');
const textContent = document.createElement('span');
textContent.classList.add('text_arlet-loadding__text');
textContent.textContent = texto;
textWrapper.appendChild(textContent);
this.loadding.append(spin, textWrapper);
this.container.appendChild(this.loadding);
}
cerrar() {
if (this.loadding) {
this.loadding.remove();
this.loadding = null;
}
}
_parseImageTipo(tipo) {
if (typeof tipo !== 'string') {
return null;
}
const trimmedTipo = tipo.trim();
if (!trimmedTipo.toLowerCase().startsWith('img-')) {
return null;
}
let remainder = trimmedTipo.slice(4).trim();
let rotate = false;
let axis = null;
let width;
let height;
const consume = (keyword) => {
if (remainder.toLowerCase().startsWith(keyword)) {
remainder = remainder.slice(keyword.length).trimStart();
return true;
}
return false;
};
if (consume('rotate-')) {
rotate = true;
if (consume('vertical-')) {
axis = 'vertical';
} else if (consume('horizontal-')) {
axis = 'horizontal';
}
}
const sizeMatch = remainder.match(/\{([^}]*)\}\s*$/);
if (sizeMatch) {
const sizeContent = sizeMatch[1];
remainder = remainder.slice(0, sizeMatch.index).trimEnd();
const normalizeSize = (input) => {
if (/^\d+(\.\d+)?$/.test(input)) {
return `${input}px`;
}
return input;
};
sizeContent.split(',').forEach((chunk) => {
if (!chunk) {
return;
}
const [rawKey, rawValue] = chunk.split(':');
if (!rawKey || !rawValue) {
return;
}
const key = rawKey.trim().toLowerCase();
const value = rawValue.trim();
if (!value) {
return;
}
if (key === 'w' || key === 'width') {
width = normalizeSize(value);
} else if (key === 'h' || key === 'height') {
height = normalizeSize(value);
}
});
}
const pathCandidate = remainder.trim();
if (!pathCandidate) {
return null;
}
let path = pathCandidate;
if (pathCandidate.startsWith('[')) {
const closingIndex = pathCandidate.indexOf(']');
if (closingIndex === -1) {
return null;
}
path = pathCandidate.slice(1, closingIndex).trim();
if (!path) {
return null;
}
const leftover = pathCandidate.slice(closingIndex + 1).trim();
if (leftover) {
return null;
}
}
return {
path,
rotate,
axis,
width,
height,
};
}
_buildImageSpin({ spin, imageConfig, texto }) {
this.loadding.classList.add('image-type');
if (imageConfig.rotate) {
if (imageConfig.axis === 'vertical') {
this.loadding.classList.add('image-rotate-vertical');
} else if (imageConfig.axis === 'horizontal') {
this.loadding.classList.add('image-rotate-horizontal');
} else {
this.loadding.classList.add('image-rotate');
}
}
spin.classList.add('image-spin');
const wrapper = document.createElement('div');
wrapper.classList.add('image-wrapper');
if (imageConfig.width || imageConfig.height) {
wrapper.classList.add('image-wrapper--custom-size');
}
const image = document.createElement('img');
image.src = imageConfig.path;
image.alt = texto || 'Cargando';
if (imageConfig.width) {
const widthAttr = this._normalizeDimensionAttribute(imageConfig.width);
if (widthAttr !== null) {
image.setAttribute('width', widthAttr);
}
}
if (imageConfig.height) {
const heightAttr = this._normalizeDimensionAttribute(imageConfig.height);
if (heightAttr !== null) {
image.setAttribute('height', heightAttr);
}
}
wrapper.appendChild(image);
spin.appendChild(wrapper);
}
_buildIaSpin({ spin }) {
const face = document.createElement('div');
face.classList.add('ia-face');
const antenna = document.createElement('div');
antenna.classList.add('ia-face__antenna');
face.appendChild(antenna);
const eyes = document.createElement('div');
eyes.classList.add('ia-face__eyes');
for (let i = 0; i < 2; i += 1) {
const eye = document.createElement('span');
eye.classList.add('ia-face__eye');
eye.style.setProperty('--eye-index', `${i}`);
eyes.appendChild(eye);
}
const mouth = document.createElement('div');
mouth.classList.add('ia-face__mouth');
for (let i = 0; i < 3; i += 1) {
const bar = document.createElement('span');
bar.classList.add('ia-face__mouth-bar');
bar.style.setProperty('--delay', `${i * 0.18}s`);
mouth.appendChild(bar);
}
face.appendChild(eyes);
face.appendChild(mouth);
spin.appendChild(face);
}
_buildRobotSpin({ spin }) {
const robot = document.createElement('div');
robot.classList.add('robot-loader');
const antenna = document.createElement('div');
antenna.classList.add('robot-loader__antenna');
robot.appendChild(antenna);
const head = document.createElement('div');
head.classList.add('robot-loader__head');
const visor = document.createElement('div');
visor.classList.add('robot-loader__visor');
for (let i = 0; i < 2; i += 1) {
const eye = document.createElement('span');
eye.classList.add('robot-loader__eye');
eye.style.setProperty('--eye-index', `${i}`);
visor.appendChild(eye);
}
const scan = document.createElement('span');
scan.classList.add('robot-loader__scan');
visor.appendChild(scan);
const mouth = document.createElement('div');
mouth.classList.add('robot-loader__mouth');
for (let i = 0; i < 3; i += 1) {
const bar = document.createElement('span');
bar.classList.add('robot-loader__mouth-bar');
bar.style.setProperty('--delay', `${i * 0.18}s`);
mouth.appendChild(bar);
}
head.appendChild(visor);
head.appendChild(mouth);
const body = document.createElement('div');
body.classList.add('robot-loader__body');
const core = document.createElement('div');
core.classList.add('robot-loader__core');
const panel = document.createElement('div');
panel.classList.add('robot-loader__panel');
for (let i = 0; i < 3; i += 1) {
const led = document.createElement('span');
led.classList.add('robot-loader__panel-led');
led.style.setProperty('--delay', `${i * 0.22}s`);
panel.appendChild(led);
}
body.append(core, panel);
robot.append(head, body);
spin.appendChild(robot);
}
_buildBikeSpin({ spin }) {
const bike = document.createElement('div');
bike.classList.add('bike-loader');
const frame = document.createElement('div');
frame.classList.add('bike-loader__frame');
const topBar = document.createElement('span');
topBar.classList.add('bike-loader__bar', 'bike-loader__bar--top');
const seatBar = document.createElement('span');
seatBar.classList.add('bike-loader__bar', 'bike-loader__bar--seat');
const downBar = document.createElement('span');
downBar.classList.add('bike-loader__bar', 'bike-loader__bar--down');
const chainBar = document.createElement('span');
chainBar.classList.add('bike-loader__bar', 'bike-loader__bar--chain');
frame.append(topBar, seatBar, downBar, chainBar);
bike.appendChild(frame);
for (let i = 0; i < 2; i += 1) {
const wheel = document.createElement('div');
wheel.classList.add('bike-loader__wheel');
wheel.classList.add(i === 0 ? 'bike-loader__wheel--back' : 'bike-loader__wheel--front');
wheel.style.setProperty('--index', `${i}`);
const spokes = document.createElement('span');
spokes.classList.add('bike-loader__spokes');
wheel.appendChild(spokes);
bike.appendChild(wheel);
}
const pedal = document.createElement('div');
pedal.classList.add('bike-loader__pedal');
for (let i = 0; i < 2; i += 1) {
const arm = document.createElement('span');
arm.classList.add('bike-loader__pedal-arm');
if (i === 1) {
arm.classList.add('bike-loader__pedal-arm--counter');
}
pedal.appendChild(arm);
}
const seat = document.createElement('div');
seat.classList.add('bike-loader__seat');
const handle = document.createElement('div');
handle.classList.add('bike-loader__handle');
bike.append(pedal, seat, handle);
spin.appendChild(bike);
}
_buildMotorBikeSpin({ spin }) {
const moto = document.createElement('div');
moto.classList.add('motor-bike-loader');
const body = document.createElement('div');
body.classList.add('motor-bike-loader__body');
const tank = document.createElement('span');
tank.classList.add('motor-bike-loader__tank');
const seat = document.createElement('span');
seat.classList.add('motor-bike-loader__seat');
const light = document.createElement('span');
light.classList.add('motor-bike-loader__light');
body.append(tank, seat, light);
moto.appendChild(body);
for (let i = 0; i < 2; i += 1) {
const wheel = document.createElement('div');
wheel.classList.add('motor-bike-loader__wheel');
wheel.classList.add(i === 0 ? 'motor-bike-loader__wheel--back' : 'motor-bike-loader__wheel--front');
wheel.style.setProperty('--index', `${i}`);
const rim = document.createElement('span');
rim.classList.add('motor-bike-loader__rim');
wheel.appendChild(rim);
moto.appendChild(wheel);
}
const smoke = document.createElement('div');
smoke.classList.add('motor-bike-loader__smoke');
for (let i = 0; i < 3; i += 1) {
const puff = document.createElement('span');
puff.classList.add('motor-bike-loader__smoke-puff');
puff.style.setProperty('--delay', `${i * 0.3}s`);
smoke.appendChild(puff);
}
moto.appendChild(smoke);
spin.appendChild(moto);
}
_buildWeavesSpin({ spin }) {
const weaves = document.createElement('div');
weaves.classList.add('weaves-loader');
for (let i = 0; i < 4; i += 1) {
const strand = document.createElement('span');
strand.classList.add('weaves-loader__strand');
strand.style.setProperty('--index', `${i}`);
weaves.appendChild(strand);
}
spin.appendChild(weaves);
}
_buildGlassRingSpin({ spin }) {
const ring = document.createElement('div');
ring.classList.add('glass-ring-loader');
const inner = document.createElement('span');
inner.classList.add('glass-ring-loader__inner');
const runner = document.createElement('span');
runner.classList.add('glass-ring-loader__runner');
ring.append(inner, runner);
spin.appendChild(ring);
}
_buildGradientBarSpin({ spin }) {
const bar = document.createElement('div');
bar.classList.add('gradient-bar-loader');
const track = document.createElement('div');
track.classList.add('gradient-bar-loader__track');
const indicator = document.createElement('div');
indicator.classList.add('gradient-bar-loader__indicator');
const glow = document.createElement('div');
glow.classList.add('gradient-bar-loader__glow');
bar.append(track, indicator, glow);
spin.appendChild(bar);
}
_buildDualPulseSpin({ spin }) {
const pulse = document.createElement('div');
pulse.classList.add('dual-pulse-loader');
for (let i = 0; i < 2; i += 1) {
const circle = document.createElement('span');
circle.classList.add('dual-pulse-loader__circle');
circle.style.setProperty('--index', `${i}`);
pulse.appendChild(circle);
}
spin.appendChild(pulse);
}
_buildLineWaveSpin({ spin }) {
const wave = document.createElement('div');
wave.classList.add('line-wave-loader');
for (let i = 0; i < 6; i += 1) {
const segment = document.createElement('span');
segment.classList.add('line-wave-loader__segment');
segment.style.setProperty('--index', `${i}`);
wave.appendChild(segment);
}
spin.appendChild(wave);
}
_normalizeDimensionAttribute(dimension) {
if (typeof dimension !== 'string') {
return null;
}
const trimmed = dimension.trim();
if (!trimmed) {
return null;
}
const pxMatch = trimmed.match(/^(\d+(?:\.\d+)?)px$/i);
if (pxMatch) {
return pxMatch[1];
}
if (/^\d+(?:\.\d+)?$/.test(trimmed)) {
return trimmed;
}
return trimmed;
}
}