|
import { clsx, type ClassValue } from 'clsx' |
|
import { twMerge } from 'tailwind-merge' |
|
import { StoreApi, UseBoundStore } from 'zustand' |
|
|
|
export function cn(...inputs: ClassValue[]) { |
|
return twMerge(clsx(inputs)) |
|
} |
|
|
|
export function randomColor() { |
|
const digits = '0123456789abcdef' |
|
let code = '#' |
|
for (let i = 0; i < 6; i++) { |
|
code += digits.charAt(Math.floor(Math.random() * 16)) |
|
} |
|
return code |
|
} |
|
|
|
export function errorMessage(error: any) { |
|
return error instanceof Error ? error.message : `${error}` |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function throttle<T extends (...args: any[]) => any>(fn: T, delay: number): (...args: Parameters<T>) => void { |
|
let lastCall = 0 |
|
let timeoutId: ReturnType<typeof setTimeout> | null = null |
|
|
|
return function(this: any, ...args: Parameters<T>) { |
|
const now = Date.now() |
|
const remaining = delay - (now - lastCall) |
|
|
|
if (remaining <= 0) { |
|
|
|
if (timeoutId) { |
|
clearTimeout(timeoutId) |
|
timeoutId = null |
|
} |
|
lastCall = now |
|
fn.apply(this, args) |
|
} else if (!timeoutId) { |
|
|
|
timeoutId = setTimeout(() => { |
|
lastCall = Date.now() |
|
timeoutId = null |
|
fn.apply(this, args) |
|
}, remaining) |
|
} |
|
} |
|
} |
|
|
|
type WithSelectors<S> = S extends { getState: () => infer T } |
|
? S & { use: { [K in keyof T]: () => T[K] } } |
|
: never |
|
|
|
export const createSelectors = <S extends UseBoundStore<StoreApi<object>>>(_store: S) => { |
|
const store = _store as WithSelectors<typeof _store> |
|
store.use = {} |
|
for (const k of Object.keys(store.getState())) { |
|
;(store.use as any)[k] = () => store((s) => s[k as keyof typeof s]) |
|
} |
|
|
|
return store |
|
} |
|
|