Packages
pui
1.0.0-alpha.17
1.0.0-beta.18
1.0.0-beta.17
1.0.0-beta.16
1.0.0-beta.15
1.0.0-beta.14
1.0.0-beta.13
1.0.0-beta.12
1.0.0-beta.11
1.0.0-beta.10
1.0.0-beta.9
1.0.0-beta.8
1.0.0-beta.7
1.0.0-beta.6
1.0.0-beta.5
1.0.0-beta.4
1.0.0-beta.3
1.0.0-beta.1
1.0.0-alpha.32
1.0.0-alpha.31
1.0.0-alpha.30
1.0.0-alpha.29
1.0.0-alpha.28
1.0.0-alpha.27
1.0.0-alpha.26
1.0.0-alpha.25
1.0.0-alpha.24
1.0.0-alpha.23
1.0.0-alpha.22
1.0.0-alpha.21
1.0.0-alpha.19
1.0.0-alpha.18
1.0.0-alpha.17
1.0.0-alpha.16
1.0.0-alpha.15
1.0.0-alpha.14
1.0.0-alpha.13
1.0.0-alpha.12
1.0.0-alpha.11
A Phoenix LiveView UI toolkit
Current section
Files
Jump to
Current section
Files
assets/js/loading.js
import { ViewHook } from "phoenix_live_view";
State = {
IDLE: 0,
STARTING: 1,
};
export default class LoadingBar extends ViewHook {
progress = 0;
delay = 300;
delayTimer = null;
raf = null;
state = State.IDLE;
#boundShow = null;
#boundHide = null;
mounted() {
this.progressEl = this.el.querySelector("#loadingbar-progress");
this.delay = parseInt(this.el.dataset.delay || "0") || this.delay;
this.#boundShow = this._show.bind(this);
this.#boundHide = this._hide.bind(this);
this.state = State.IDLE;
window.addEventListener("phx:page-loading-start", this.#boundShow);
window.addEventListener("phx:page-loading-stop", this.#boundHide);
}
_show(info) {
this._clear();
this.delayTimer = setTimeout(() => {
if (this.state === State.IDLE) {
this.state = State.STARTING;
this._start();
}
}, this.delay);
}
_start() {
let lastTime = performance.now();
const step = (now) => {
const dt = now - lastTime;
lastTime = now;
if (this.progress < 50) {
const delta = (100 - this.progress) * 0.01 * (dt / 16);
this.progress = Math.min(this.progress + delta, 50);
} else if (this.progress < 90) {
const delta = (100 - this.progress) * 0.0025 * (dt / 16);
this.progress = Math.min(this.progress + delta, 90);
} else if (this.progress < 99) {
const delta = (100 - this.progress) * 0.0005 * (dt / 16);
this.progress = Math.min(this.progress + delta, 99);
}
this.progressEl.style.width = `${this.progress}%`;
this.raf = requestAnimationFrame(step);
};
this.raf = requestAnimationFrame(step);
}
_reset() {
this.progressEl.style.transition = "none";
this.progressEl.style.width = "0%";
this.progressEl.offsetHeight; // force reflow
this.progressEl.style.transition = "";
this.progress = 0;
this._clear();
this.state = State.IDLE;
cancelAnimationFrame(this.raf);
}
_hide(info) {
this.state = State.IDLE;
this._clear();
if (this.progress > 0) {
this.progress = 100;
this.progressEl.style.width = "100%";
}
setTimeout(() => {
this._reset();
}, 500);
}
_clear() {
if (this.delayTimer) {
clearTimeout(this.delayTimer);
this.delayTimer = null;
}
}
destroyed() {
window.removeEventListener("phx:page-loading-start", this.#boundShow);
window.removeEventListener("phx:page-loading-stop", this.#boundHide);
}
}