UNPKG

flyonui

Version:

The easiest, free and open-source Tailwind CSS component library with semantic classes.

141 lines (105 loc) 4.06 kB
/* * HSToggleCount * @version: 3.2.2 * @author: Preline Labs Ltd. * @license: Licensed under MIT and Preline UI Fair Use License (https://preline.co/docs/license.html) * Copyright 2024 Preline Labs Ltd. */ import { IToggleCountOptions, IToggleCount } from './interfaces' import HSBasePlugin from '../base-plugin' import { ICollectionItem } from '../../interfaces' class HSToggleCount extends HSBasePlugin<IToggleCountOptions> implements IToggleCount { private readonly target: HTMLInputElement | null private readonly min: number | null private readonly max: number | null private readonly duration: number | null private isChecked: boolean private onToggleChangeListener: () => void constructor(el: HTMLElement, options?: IToggleCountOptions) { super(el, options) const data = el.getAttribute('data-toggle-count') const dataOptions: IToggleCountOptions = data ? JSON.parse(data) : {} const concatOptions = { ...dataOptions, ...options } this.target = concatOptions?.target ? typeof concatOptions?.target === 'string' ? (document.querySelector(concatOptions.target) as HTMLInputElement) : concatOptions.target : null this.min = concatOptions?.min || 0 this.max = concatOptions?.max || 0 this.duration = concatOptions?.duration || 700 this.isChecked = (this.target as HTMLInputElement).checked || false if (this.target) this.init() } private toggleChange() { this.isChecked = !this.isChecked this.toggle() } private init() { this.createCollection(window.$hsToggleCountCollection, this) if (this.isChecked) this.el.innerText = String(this.max) this.onToggleChangeListener = () => this.toggleChange() this.target.addEventListener('change', this.onToggleChangeListener) } private toggle() { if (this.isChecked) this.countUp() else this.countDown() } private animate(from: number, to: number) { let startTimestamp = 0 const step = (timestamp: number) => { if (!startTimestamp) startTimestamp = timestamp const progress = Math.min((timestamp - startTimestamp) / this.duration, 1) this.el.innerText = String(Math.floor(progress * (to - from) + from)) if (progress < 1) window.requestAnimationFrame(step) } window.requestAnimationFrame(step) } // Public methods public countUp() { this.animate(this.min, this.max) } public countDown() { this.animate(this.max, this.min) } public destroy() { // Remove listeners this.target.removeEventListener('change', this.onToggleChangeListener) window.$hsToggleCountCollection = window.$hsToggleCountCollection.filter(({ element }) => element.el !== this.el) } // Static methods static getInstance(target: HTMLElement | string, isInstance?: boolean) { const elInCollection = window.$hsToggleCountCollection.find( el => el.element.el === (typeof target === 'string' ? document.querySelector(target) : target) ) return elInCollection ? (isInstance ? elInCollection : elInCollection.element) : null } static autoInit() { if (!window.$hsToggleCountCollection) window.$hsToggleCountCollection = [] if (window.$hsToggleCountCollection) window.$hsToggleCountCollection = window.$hsToggleCountCollection.filter(({ element }) => document.contains(element.el) ) document.querySelectorAll('[data-toggle-count]:not(.--prevent-on-load-init)').forEach((el: HTMLElement) => { if (!window.$hsToggleCountCollection.find(elC => (elC?.element?.el as HTMLElement) === el)) new HSToggleCount(el) }) } } declare global { interface Window { HSToggleCount: Function $hsToggleCountCollection: ICollectionItem<HSToggleCount>[] } } window.addEventListener('load', () => { HSToggleCount.autoInit() // Uncomment for debug // console.log('Toggle count collection:', window.$hsToggleCountCollection); }) if (typeof window !== 'undefined') { window.HSToggleCount = HSToggleCount } export default HSToggleCount