import { LitElement } from "lit"; import { property, state } from "lit/decorators.js"; import { msg, localized, str } from "@lit/localize"; import humanizeDuration from "pretty-ms"; export type HumanizeOptions = { compact?: boolean; verbose?: boolean; unitCount?: number; }; /** * Show time passed from date in human-friendly format * * Usage example: * ```ts * * ``` */ @localized() export class RelativeDuration extends LitElement { @property({ type: String }) value?: string; // `new Date` compatible date format @property({ type: Number }) tickSeconds?: number; // Enables ticks every specified seconds @property({ type: Number }) endTime?: number = Date.now(); @property({ type: Boolean }) compact? = false; @property({ type: Boolean }) verbose? = false; @property({ type: Number }) unitCount?: number; @state() private timerId?: number; static humanize(duration: number, options: HumanizeOptions = {}) { return humanizeDuration(duration, { secondsDecimalDigits: 0, ...options, }); } connectedCallback(): void { super.connectedCallback(); } disconnectedCallback(): void { window.clearTimeout(this.timerId); super.disconnectedCallback(); } protected updated(changedProperties: Map) { if (changedProperties.has("tickSeconds")) { window.clearTimeout(this.timerId); } if (changedProperties.has("endTime") && this.tickSeconds) { this.tick(this.tickSeconds * 1000); } } private tick(timeoutMs: number) { window.clearTimeout(this.timerId); this.timerId = window.setTimeout(() => { this.endTime = Date.now(); }, timeoutMs); } render() { if (!this.value) return ""; return RelativeDuration.humanize( (this.endTime || Date.now()) - new Date(this.value).valueOf(), { compact: this.compact, verbose: this.verbose, unitCount: this.unitCount, } ); } }