UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

240 lines (203 loc) 6.29 kB
// Utility Functions Export // Re-export all utility functions for easy consumption export * from './api'; export * from './auth'; export * from './validation'; export * from './storage'; export * from './crypto'; export * from './url'; export * from './format'; export * from './error'; export * from './theme'; // Common utility functions export const sleep = (ms: number): Promise<void> => new Promise(resolve => setTimeout(resolve, ms)); export const debounce = <T extends (...args: any[]) => any>( func: T, wait: number, immediate?: boolean ): ((...args: Parameters<T>) => void) => { let timeout: NodeJS.Timeout | null = null; return (...args: Parameters<T>) => { const later = () => { timeout = null; if (!immediate) func(...args); }; const callNow = immediate && !timeout; if (timeout) clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func(...args); }; }; export const throttle = <T extends (...args: any[]) => any>( func: T, limit: number ): ((...args: Parameters<T>) => void) => { let inThrottle: boolean; return (...args: Parameters<T>) => { if (!inThrottle) { func(...args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; }; export const omit = <T extends Record<string, any>, K extends keyof T>( obj: T, keys: K[] ): Omit<T, K> => { const result = { ...obj }; for (const key of keys) { delete result[key]; } return result; }; export const pick = <T extends Record<string, any>, K extends keyof T>( obj: T, keys: K[] ): Pick<T, K> => { const result = {} as Pick<T, K>; for (const key of keys) { if (key in obj) { result[key] = obj[key]; } } return result; }; export const isEmpty = (value: any): boolean => { if (value == null) return true; if (typeof value === 'string') return value.length === 0; if (Array.isArray(value)) return value.length === 0; if (typeof value === 'object') return Object.keys(value).length === 0; return false; }; export const isEqual = (a: any, b: any): boolean => { if (a === b) return true; if (a == null || b == null) return false; if (typeof a !== typeof b) return false; if (Array.isArray(a)) { if (!Array.isArray(b) || a.length !== b.length) return false; return a.every((val, index) => isEqual(val, b[index])); } if (typeof a === 'object') { const keysA = Object.keys(a); const keysB = Object.keys(b); if (keysA.length !== keysB.length) return false; return keysA.every(key => isEqual(a[key], b[key])); } return false; }; export const generateId = (): string => { return Math.random().toString(36).substring(2) + Date.now().toString(36); }; export const clamp = (value: number, min: number, max: number): number => { return Math.min(Math.max(value, min), max); }; export const arrayToObject = <T>( array: T[], keyFn: (item: T) => string ): Record<string, T> => { return array.reduce((acc, item) => { acc[keyFn(item)] = item; return acc; }, {} as Record<string, T>); }; export const groupBy = <T>( array: T[], keyFn: (item: T) => string ): Record<string, T[]> => { return array.reduce((acc, item) => { const key = keyFn(item); if (!acc[key]) acc[key] = []; acc[key].push(item); return acc; }, {} as Record<string, T[]>); }; export const unique = <T>(array: T[]): T[] => { return [...new Set(array)]; }; export const uniqueBy = <T>(array: T[], keyFn: (item: T) => any): T[] => { const seen = new Set(); return array.filter(item => { const key = keyFn(item); if (seen.has(key)) return false; seen.add(key); return true; }); }; export const capitalize = (str: string): string => { return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); }; export const camelCase = (str: string): string => { return str .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => { return index === 0 ? word.toLowerCase() : word.toUpperCase(); }) .replace(/\s+/g, ''); }; export const kebabCase = (str: string): string => { return str .replace(/([a-z])([A-Z])/g, '$1-$2') .replace(/[\s_]+/g, '-') .toLowerCase(); }; export const snakeCase = (str: string): string => { return str .replace(/([a-z])([A-Z])/g, '$1_$2') .replace(/[\s-]+/g, '_') .toLowerCase(); }; export const truncate = (str: string, length: number, suffix = '...'): string => { if (str.length <= length) return str; return str.substring(0, length - suffix.length) + suffix; }; export const randomInt = (min: number, max: number): number => { return Math.floor(Math.random() * (max - min + 1)) + min; }; export const randomChoice = <T>(array: T[]): T => { return array[randomInt(0, array.length - 1)]; }; export const retry = async <T>( fn: () => Promise<T>, maxAttempts = 3, delay = 1000 ): Promise<T> => { let lastError: Error; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (error) { lastError = error as Error; if (attempt === maxAttempts) break; await sleep(delay * attempt); } } throw lastError!; }; export const withTimeout = <T>( promise: Promise<T>, timeoutMs: number, errorMessage = 'Operation timed out' ): Promise<T> => { return Promise.race([ promise, new Promise<never>((_, reject) => setTimeout(() => reject(new Error(errorMessage)), timeoutMs) ), ]); }; export const memoize = <T extends (...args: any[]) => any>( fn: T, keyFn?: (...args: Parameters<T>) => string ): T => { const cache = new Map(); return ((...args: Parameters<T>) => { const key = keyFn ? keyFn(...args) : JSON.stringify(args); if (cache.has(key)) { return cache.get(key); } const result = fn(...args); cache.set(key, result); return result; }) as T; };