Skip to content

TS rewrite #253

@kharrat

Description

@kharrat

Hello,

I wrote a typescript rewrite to the main file if any one interested

/**
 * NProgress is a lightweight progress bar for JS applications.
 * It provides a simple way to visualize loading states with a slim progress bar at the top of the page.
 *
 * This is implemented as a singleton, so you should access it via NProgress.getInstance() or use the default export.
 *
 * @example
 * // Start the progress bar
 * NProgress.start();
 *
 * // Set progress to 50%
 * NProgress.set(0.5);
 *
 * // Increment the progress bar
 * NProgress.inc();
 *
 * // Complete the progress
 * NProgress.done();
 *
 * // Configure options
 * NProgress.configure({ showSpinner: false });
 */

type NProgressSettings = {
  minimum: number;
  easing?: string;
  positionUsing?: string;
  speed?: number;
  trickle?: boolean;
  trickleSpeed?: number;
  showSpinner?: boolean;
  barSelector: string;
  spinnerSelector?: string;
  parent: string;
  template: string;
};

export class NProgress {
  private static instance: NProgress;
  private status: number | null = null;

  // Default settings
  private settings: NProgressSettings = {
    minimum: 0.08,
    easing: "linear",
    positionUsing: "",
    speed: 200,
    trickle: true,
    trickleSpeed: 200,
    showSpinner: true,
    barSelector: '[role="bar"]',
    spinnerSelector: '[role="spinner"]',
    parent: "body",
    template:
      '<div class="bar" role="bar"><div class="peg"></div></div>' +
      '<div class="spinner" role="spinner"><div class="spinner-icon"></div></div>',
  };

  private constructor() {}

  public static getInstance() {
    if (!NProgress.instance) {
      NProgress.instance = new NProgress();
    }
    return NProgress.instance;
  }

  public configure(options: Partial<NProgressSettings>) {
    Object.assign(this.settings, options);
    return this;
  }

  public start(): NProgress {
    if (!this.status) this.set(0);

    const work = () => {
      setTimeout(() => {
        if (!this.status) return;
        this.trickle();
        work();
      }, this.settings.trickleSpeed);
    };

    if (this.settings.trickle) work();
    return this;
  }

  public set(n: number): NProgress {
    const started = this.isStarted();
    n = this.clamp(n, this.settings.minimum || 0.08, 1);
    this.status = n === 1 ? null : n;

    const progress = this.render(!started);
    const bar = progress.querySelector<HTMLElement>(this.settings.barSelector);
    const speed = this.settings.speed || 200;
    const ease = this.settings.easing || "linear";

    if (bar) {
      this.applyCss(bar, this.barPositionCSS(n, speed, ease));
    }

    if (n === 1) {
      setTimeout(() => {
        this.remove();
      }, speed);
    }

    return this;
  }

  public done(force = false): NProgress {
    if (!force && !this.status) return this;
    return this.inc(0.3 + 0.5 * Math.random()).set(1);
  }

  public inc(amount?: number): NProgress {
    let n = this.status ?? 0;

    if (n >= 1) return this;
    amount =
      amount ?? (n < 0.2 ? 0.1 : n < 0.5 ? 0.04 : n < 0.8 ? 0.02 : 0.005);

    return this.set(this.clamp(n + amount, 0, 0.994));
  }

  public trickle(): NProgress {
    return this.inc();
  }

  private isStarted(): boolean {
    return typeof this.status === "number";
  }

  private render(fromStart = false): HTMLElement {
    if (this.isRendered()) return document.getElementById("nprogress")!;

    const progress = document.createElement("div");
    progress.id = "nprogress";
    progress.innerHTML = this.settings.template;

    document.querySelector(this.settings.parent)!.appendChild(progress);
    return progress;
  }

  private remove(): void {
    const progress = document.getElementById("nprogress");
    progress?.parentNode?.removeChild(progress);
  }

  private isRendered(): boolean {
    return !!document.getElementById("nprogress");
  }

  private clamp(n: number, min: number, max: number): number {
    return Math.min(Math.max(n, min), max);
  }

  private barPositionCSS(
    n: number,
    speed: number,
    ease: string
  ): Record<string, string> {
    return {
      transform: `translate3d(${(-1 + n) * 100}%,0,0)`,
      transition: `all ${speed}ms ${ease}`,
    };
  }

  private applyCss(element: HTMLElement, styles: Record<string, string>): void {
    Object.assign(element.style, styles);
  }
}

export default NProgress.getInstance();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions