Files
housesof/src/utils/functions/index.ts
2022-09-25 14:29:19 +02:00

163 lines
4.0 KiB
TypeScript

/**
* Throttle function
*/
export const throttle = (func: Function, timeout: number) => {
let ready: boolean = true
return (...args: any) => {
if (!ready) return
ready = false
func(...args)
setTimeout(() => ready = true, timeout)
}
}
/**
* Debounce function
*/
export const debounce = (func: Function, timeout: number) => {
let timer: NodeJS.Timeout
return (...args: any) => {
clearTimeout(timer)
timer = setTimeout(() => func(...args), timeout)
}
}
/**
* Split text
* @description Split a string into words or characters
* @returns string[]
*/
export const splitText = (text: string, mode: string = 'words'): string[] => {
// Split by words
if (mode === 'words') {
const words = text
.replace(/\\n/g, '\n')
.replace(/\s+/g, m => m.includes('\n') ? '\n ' : ' ')
.trim()
.split(' ')
return words
}
// Split by chars
else if (mode === 'chars') {
const chars = Array.from(text).map(char => char === ' ' ? '\xa0' : char)
return chars
}
}
/**
* Capitalize first letter
*/
export const capitalizeFirstLetter = (string: string) => {
return string[0].toUpperCase() + string.slice(1)
}
/**
* Create a delay
*/
export const sleep = (milliseconds: number) => {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
/**
* Linear Interpolation
*/
export const lerp = (start: number, end: number, amount: number): number => {
return (1 - amount) * start + amount * end
}
/**
* Re-maps a number from one range to another
* @param value the incoming value to be converted
* @param start1 lower bound of the value's current range
* @param stop1 upper bound of the value's current range
* @param start2 lower bound of the value's target range
* @param stop2 upper bound of the value's target range
* @param [withinBounds] constrain the value to the newly mapped range
* @return remapped number
*/
export const map = (n: number, start1: number, stop1: number, start2: number, stop2: number, withinBounds: boolean): number => {
const value = (n - start1) / (stop1 - start1) * (stop2 - start2) + start2
if (!withinBounds) return value
if (start2 < stop2) {
return clamp(value, start2, stop2)
} else {
return clamp(value, stop2, start2)
}
}
/**
* Clamp a number
*/
export const clamp = (num: number, a: number, b: number) => {
return Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b))
}
/**
* Return a random element from an array
*/
export const getRandomItem = <T extends unknown> (array: T[]): T => {
const randomItemIndex = ~~(array.length * Math.random())
return array[randomItemIndex]
}
/**
* Return random elements from an array
*/
export const getRandomItems = <T extends unknown> (array: any[], amount: number): T[] => {
const shuffled = Array.from(array).sort(() => 0.5 - Math.random())
return shuffled.slice(0, amount)
}
/**
* Scroll back to top after page transition
*/
export const scrollToTop = (delay?: number) => {
const scroll = () => window.scrollTo(0,0)
if (delay && delay > 0) {
setTimeout(scroll, delay)
} else {
scroll()
}
}
/**
* Copy mailto links to clipboard and show message
*/
export const mailtoClipboard = (node: HTMLElement) => {
const links = node.querySelectorAll('a[href^="mailto:"]')
const clickToCopy = (event) => {
let emailAddress = event.currentTarget.href.split('mailto:')[1].split('?')[0]
// Copy email to clipboard
navigator.clipboard.writeText(emailAddress)
// Send event
node.dispatchEvent(new CustomEvent('copied', {
detail: { email: emailAddress }
}))
event.preventDefault()
}
links && links.forEach(link => link.addEventListener('click', clickToCopy, true))
return {
destroy () {
links && links.forEach(link => link.removeEventListener('click', clickToCopy, true))
}
}
}