UNPKG

@rxxuzi/gumi

Version:

Clean & minimal design system with delightful interactions

227 lines 6.79 kB
// components/progress.ts // Gumi.js v1.0.0 - Progress Bar Component import { $, addClass, removeClass } from '../core/dom'; import { clamp } from '../utils/helpers'; export class Progress { constructor(element, options) { var _a; this.value = 0; const el = $(element); if (!el) throw new Error('Progress element not found'); // Check if element is container or bar if (el.classList.contains('progress')) { this.container = el; this.bar = el.querySelector('.progress-bar'); if (!this.bar) { // Create bar if it doesn't exist this.bar = document.createElement('div'); this.bar.className = 'progress-bar'; this.container.appendChild(this.bar); } } else if (el.classList.contains('progress-bar')) { this.bar = el; this.container = el.parentElement; } else { // Assume it's a bar element this.bar = el; this.container = el.parentElement; } this.options = { animated: false, striped: false, ...options, value: (_a = options.value) !== null && _a !== void 0 ? _a : 0 }; this.init(); } /** * Initialize progress bar */ init() { // Set ARIA attributes this.bar.setAttribute('role', 'progressbar'); this.bar.setAttribute('aria-valuemin', '0'); this.bar.setAttribute('aria-valuemax', '100'); // Apply options if (this.options.striped) { addClass(this.container, 'progress-striped'); } if (this.options.animated) { addClass(this.container, 'progress-animated'); } // Set initial value this.setValue(this.options.value); } /** * Set progress value */ setValue(value) { // Clamp value between 0 and 100 this.value = clamp(value, 0, 100); // Update bar width this.bar.style.width = `${this.value}%`; this.bar.setAttribute('aria-valuenow', String(this.value)); // Auto color based on percentage this.updateColor(); } /** * Get current value */ getValue() { return this.value; } /** * Update color based on value */ updateColor() { let color; if (this.value < 25) { color = 'var(--gumi-error)'; } else if (this.value < 50) { color = 'var(--gumi-warning)'; } else if (this.value < 75) { color = 'var(--gumi-secondary)'; } else { color = 'var(--gumi-success)'; } this.bar.style.backgroundColor = color; } /** * Increment progress */ increment(amount = 1) { this.setValue(this.value + amount); } /** * Decrement progress */ decrement(amount = 1) { this.setValue(this.value - amount); } /** * Set to indeterminate state */ setIndeterminate(indeterminate = true) { if (indeterminate) { this.bar.style.width = '100%'; addClass(this.container, 'progress-indeterminate'); this.bar.removeAttribute('aria-valuenow'); } else { removeClass(this.container, 'progress-indeterminate'); this.setValue(this.value); } } /** * Set striped style */ setStriped(striped = true) { if (striped) { addClass(this.container, 'progress-striped'); } else { removeClass(this.container, 'progress-striped'); } } /** * Set animated style */ setAnimated(animated = true) { if (animated) { addClass(this.container, 'progress-animated'); this.setStriped(true); // Animated requires striped } else { removeClass(this.container, 'progress-animated'); } } /** * Animate to value */ animateTo(targetValue, duration = 1000) { return new Promise((resolve) => { const startValue = this.value; const startTime = performance.now(); const animate = (currentTime) => { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); // Easing function (ease-in-out) const easing = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2; const currentValue = startValue + (targetValue - startValue) * easing; this.setValue(currentValue); if (progress < 1) { requestAnimationFrame(animate); } else { resolve(); } }; requestAnimationFrame(animate); }); } /** * Reset progress */ reset() { this.setValue(0); } /** * Complete progress */ complete() { this.setValue(100); } /** * Static helper to create progress bar */ static create(options = { value: 0 }) { const container = options.container || document.body; const progressEl = document.createElement('div'); progressEl.className = 'progress ' + (options.className || ''); const barEl = document.createElement('div'); barEl.className = 'progress-bar'; progressEl.appendChild(barEl); container.appendChild(progressEl); return new Progress(progressEl, options); } /** * Static method to set progress on element */ static setProgress(selector, value) { const el = $(selector); if (!el) return; // Check if it's a progress bar element const isBar = el.classList.contains('progress-bar'); const bar = isBar ? el : el.querySelector('.progress-bar'); if (!bar) return; const clampedValue = clamp(value, 0, 100); bar.style.width = `${clampedValue}%`; bar.setAttribute('aria-valuenow', String(clampedValue)); // Auto color let color; if (clampedValue < 25) { color = 'var(--gumi-error)'; } else if (clampedValue < 50) { color = 'var(--gumi-warning)'; } else if (clampedValue < 75) { color = 'var(--gumi-secondary)'; } else { color = 'var(--gumi-success)'; } bar.style.backgroundColor = color; } } //# sourceMappingURL=progress.js.map