@rxxuzi/gumi
Version:
Clean & minimal design system with delightful interactions
227 lines • 6.79 kB
JavaScript
// 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