Skip to content

Timer

Live islandRuns locally in this page

Page shell

<timer-element></timer-element>

<script src="./build/cami.cdn.js"></script>
<!-- CDN version below -->
<!-- <script src="https://unpkg.com/cami@0.4/build/cami.cdn.js"></script> -->
<script type="module" src="./island.js"></script>

Island source

const { html, ReactiveElement } = cami
class TimerElement extends ReactiveElement {
    elapsedTime = 0;
    duration = 15;
    timer;
    onConnect() {
        this.startTimer();
    }
    onDisconnect() {
        if (this.timer !== undefined)
            clearInterval(this.timer);
    }
    startTimer() {
        if (this.timer !== undefined)
            clearInterval(this.timer);
        this.timer = setInterval(() => {
            if (this.elapsedTime < this.duration) {
                this.elapsedTime = Math.min(this.elapsedTime + 0.1, this.duration);
            }
            if (this.elapsedTime >= this.duration && this.timer !== undefined) {
                clearInterval(this.timer);
                this.timer = undefined;
            }
        }, 100);
    }
    updateDuration(event) {
        this.duration = Number(event.currentTarget.value);
        if (this.elapsedTime < this.duration) {
            this.startTimer();
        }
        else if (this.timer !== undefined) {
            clearInterval(this.timer);
            this.timer = undefined;
        }
    }
    resetTimer() {
        this.elapsedTime = 0;
        this.startTimer();
    }
    template() {
        return html `
      <label>Elapsed Time: ${this.elapsedTime.toFixed(1)} seconds</label>
      <progress value=${this.elapsedTime} max=${this.duration}></progress>
      <label>Max Duration: ${this.duration} seconds</label>
      <input type="range" min="0" max="30" .value=${String(this.duration)} @input=${(event) => this.updateDuration(event)}>
      <button @click=${() => this.resetTimer()}>Reset</button>
    `;
    }
}
customElements.define('timer-element', TimerElement);
import { html, ReactiveElement } from 'cami'

class TimerElement extends ReactiveElement {
  elapsedTime: number = 0
  duration: number = 15
  private timer: ReturnType<typeof setInterval> | undefined

  onConnect(): void {
    this.startTimer()
  }

  onDisconnect(): void {
    if (this.timer !== undefined) clearInterval(this.timer)
  }

  startTimer(): void {
    if (this.timer !== undefined) clearInterval(this.timer)
    this.timer = setInterval(() => {
      if (this.elapsedTime < this.duration) {
        this.elapsedTime = Math.min(this.elapsedTime + 0.1, this.duration)
      }
      if (this.elapsedTime >= this.duration && this.timer !== undefined) {
        clearInterval(this.timer)
        this.timer = undefined
      }
    }, 100)
  }

  updateDuration(event: InputEvent): void {
    this.duration = Number((event.currentTarget as HTMLInputElement).value)
    if (this.elapsedTime < this.duration) {
      this.startTimer()
    } else if (this.timer !== undefined) {
      clearInterval(this.timer)
      this.timer = undefined
    }
  }

  resetTimer(): void {
    this.elapsedTime = 0
    this.startTimer()
  }

  template(): ReturnType<typeof html> {
    return html`
      <label>Elapsed Time: ${this.elapsedTime.toFixed(1)} seconds</label>
      <progress value=${this.elapsedTime} max=${this.duration}></progress>
      <label>Max Duration: ${this.duration} seconds</label>
      <input type="range" min="0" max="30" .value=${String(this.duration)} @input=${(event: InputEvent) => this.updateDuration(event)}>
      <button @click=${() => this.resetTimer()}>Reset</button>
    `
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'timer-element': TimerElement
  }
}

customElements.define('timer-element', TimerElement)