houser-js-utils
Version:
A comprehensive collection of TypeScript utility functions for common development tasks including array manipulation, string processing, date handling, random number generation, validation, and much more.
1 lines • 17.9 kB
Source Map (JSON)
{"version":3,"file":"AnimationUtils.mjs","sources":["../src/AnimationUtils.ts"],"sourcesContent":["/**\n * @module AnimationUtils\n * @description A collection of utility functions for handling animations in web applications.\n * Provides methods for CSS transitions, requestAnimationFrame animations, keyframe animations,\n * and spring physics-based animations.\n *\n * @example\n * ```typescript\n * import { AnimationUtils } from 'houser-js-utils';\n *\n * // Animate an element using CSS transitions\n * const element = document.querySelector('.box');\n * await AnimationUtils.animate(element, {\n * transform: 'translateX(100px)',\n * opacity: '0.5'\n * });\n *\n * // Create a spring animation\n * await AnimationUtils.createSpringAnimation(element, {\n * transform: 'translateY(200px)'\n * }, {\n * stiffness: 170,\n * damping: 26\n * });\n * ```\n */\n\n/**\n * Spring animation configuration options\n */\ninterface SpringOptions {\n /** Spring stiffness coefficient (default: 170) */\n stiffness?: number;\n /** Damping coefficient (default: 26) */\n damping?: number;\n /** Mass of the animated object (default: 1) */\n mass?: number;\n /** Maximum duration of the animation in milliseconds (default: 300) */\n duration?: number;\n}\n\nexport const AnimationUtils = {\n /**\n * Animates an element using CSS transitions\n * @param element - The HTML element to animate\n * @param properties - CSS properties to animate\n * @param duration - Animation duration in milliseconds (default: 300)\n * @param easing - CSS easing function (default: 'ease')\n * @returns Promise that resolves when animation completes\n * @example\n * ```typescript\n * const element = document.querySelector('.box');\n * await AnimationUtils.animate(element, {\n * transform: 'translateX(100px)',\n * opacity: '0.5'\n * }, 500, 'ease-in-out');\n * ```\n */\n animate(\n element: HTMLElement,\n properties: Partial<CSSStyleDeclaration>,\n duration = 300,\n easing = \"ease\"\n ): Promise<void> {\n return new Promise((resolve) => {\n const startValues: { [key: string]: number } = {};\n const endValues: { [key: string]: number } = {};\n\n // Get start values\n Object.keys(properties).forEach((key) => {\n const value = properties[key as keyof CSSStyleDeclaration];\n if (value !== undefined) {\n const startValue = parseFloat(\n getComputedStyle(element)[\n key as keyof CSSStyleDeclaration\n ] as string\n );\n const endValue = parseFloat(value as string);\n if (!isNaN(startValue) && !isNaN(endValue)) {\n startValues[key] = startValue;\n endValues[key] = endValue;\n }\n }\n });\n\n // Set initial transition\n element.style.transition = `all ${duration}ms ${easing}`;\n\n // Set end values\n Object.keys(properties).forEach((key) => {\n const value = properties[key as keyof CSSStyleDeclaration];\n if (value !== undefined) {\n (element.style as any)[key] = value;\n }\n });\n\n // Handle animation end\n const handleTransitionEnd = () => {\n element.removeEventListener(\"transitionend\", handleTransitionEnd);\n element.style.transition = \"\";\n resolve();\n };\n\n element.addEventListener(\"transitionend\", handleTransitionEnd);\n\n // Fallback timeout\n setTimeout(handleTransitionEnd, duration);\n });\n },\n\n /**\n * Animates an element using requestAnimationFrame for smoother animations\n * @param element - The HTML element to animate\n * @param properties - CSS properties to animate\n * @param duration - Animation duration in milliseconds (default: 300)\n * @param easing - Custom easing function (default: linear)\n * @returns Promise that resolves when animation completes\n * @example\n * ```typescript\n * const element = document.querySelector('.box');\n * await AnimationUtils.animateWithRAF(element, {\n * transform: 'translateX(100px)'\n * }, 500, (t) => t * t); // Quadratic easing\n * ```\n */\n animateWithRAF(\n element: HTMLElement,\n properties: Partial<CSSStyleDeclaration>,\n duration = 300,\n easing = (t: number) => t\n ): Promise<void> {\n return new Promise((resolve) => {\n const startTime = performance.now();\n const startValues: { [key: string]: number } = {};\n const endValues: { [key: string]: number } = {};\n\n // Get start values\n Object.keys(properties).forEach((key) => {\n const value = properties[key as keyof CSSStyleDeclaration];\n if (value !== undefined) {\n const startValue = parseFloat(\n getComputedStyle(element)[\n key as keyof CSSStyleDeclaration\n ] as string\n );\n const endValue = parseFloat(value as string);\n if (!isNaN(startValue) && !isNaN(endValue)) {\n startValues[key] = startValue;\n endValues[key] = endValue;\n }\n }\n });\n\n const animate = (currentTime: number) => {\n const elapsed = currentTime - startTime;\n const progress = Math.min(elapsed / duration, 1);\n const easedProgress = easing(progress);\n\n Object.keys(startValues).forEach((key) => {\n const startValue = startValues[key];\n const endValue = endValues[key];\n const currentValue =\n startValue + (endValue - startValue) * easedProgress;\n (element.style as any)[key] = `${currentValue}px`;\n });\n\n if (progress < 1) {\n requestAnimationFrame(animate);\n } else {\n resolve();\n }\n };\n\n requestAnimationFrame(animate);\n });\n },\n\n /**\n * Creates a keyframe animation using the Web Animations API\n * @param element - The HTML element to animate\n * @param keyframes - Array of keyframe objects\n * @param options - Animation options\n * @returns Animation object\n * @example\n * ```typescript\n * const element = document.querySelector('.box');\n * const animation = AnimationUtils.createKeyframeAnimation(element, [\n * { transform: 'translateX(0)', opacity: 1 },\n * { transform: 'translateX(100px)', opacity: 0.5 }\n * ], {\n * duration: 500,\n * easing: 'ease-in-out'\n * });\n * ```\n */\n createKeyframeAnimation(\n element: HTMLElement,\n keyframes: Keyframe[],\n options: KeyframeAnimationOptions = {}\n ): Animation {\n return element.animate(keyframes, {\n duration: 300,\n easing: \"ease\",\n fill: \"forwards\",\n ...options,\n });\n },\n\n /**\n * Creates a spring physics-based animation\n * @param element - The HTML element to animate\n * @param properties - CSS properties to animate\n * @param options - Spring animation configuration\n * @returns Promise that resolves when animation completes\n * @example\n * ```typescript\n * const element = document.querySelector('.box');\n * await AnimationUtils.createSpringAnimation(element, {\n * transform: 'translateY(200px)'\n * }, {\n * stiffness: 170,\n * damping: 26,\n * mass: 1\n * });\n * ```\n */\n createSpringAnimation(\n element: HTMLElement,\n properties: Partial<CSSStyleDeclaration>,\n options: SpringOptions = {}\n ): Promise<void> {\n const { stiffness = 170, damping = 26, mass = 1, duration = 300 } = options;\n\n return new Promise((resolve) => {\n const startTime = performance.now();\n const startValues: { [key: string]: number } = {};\n const endValues: { [key: string]: number } = {};\n const velocities: { [key: string]: number } = {};\n\n // Get start values\n Object.keys(properties).forEach((key) => {\n const value = properties[key as keyof CSSStyleDeclaration];\n if (value !== undefined) {\n const startValue = parseFloat(\n getComputedStyle(element)[\n key as keyof CSSStyleDeclaration\n ] as string\n );\n const endValue = parseFloat(value as string);\n if (!isNaN(startValue) && !isNaN(endValue)) {\n startValues[key] = startValue;\n endValues[key] = endValue;\n velocities[key] = 0;\n }\n }\n });\n\n const animate = (currentTime: number) => {\n const elapsed = currentTime - startTime;\n if (elapsed >= duration) {\n Object.keys(endValues).forEach((key) => {\n (element.style as any)[key] = `${endValues[key]}px`;\n });\n resolve();\n return;\n }\n\n Object.keys(startValues).forEach((key) => {\n const startValue = startValues[key];\n const endValue = endValues[key];\n const currentValue = parseFloat(\n (element.style as any)[key] || startValue\n );\n const velocity = velocities[key];\n\n const displacement = endValue - currentValue;\n const spring = stiffness * displacement;\n const damper = damping * velocity;\n const acceleration = (spring - damper) / mass;\n\n velocities[key] = velocity + acceleration * (elapsed / 1000);\n const newValue = currentValue + velocities[key] * (elapsed / 1000);\n (element.style as any)[key] = `${newValue}px`;\n });\n\n requestAnimationFrame(animate);\n };\n\n requestAnimationFrame(animate);\n });\n },\n\n /**\n * Gets all animations currently running on an element\n * @param element - The HTML element to check\n * @returns Array of Animation objects\n * @example\n * ```typescript\n * const element = document.querySelector('.box');\n * const animations = AnimationUtils.getAnimations(element);\n * ```\n */\n getAnimations(element: HTMLElement): Animation[] {\n return element.getAnimations();\n },\n\n /**\n * Gets the current animation state of an element\n * @param element - The HTML element to check\n * @returns Current animation state: 'idle', 'running', or 'paused'\n * @example\n * ```typescript\n * const element = document.querySelector('.box');\n * const state = AnimationUtils.getAnimationState(element);\n * if (state === 'running') {\n * console.log('Element is currently animating');\n * }\n * ```\n */\n getAnimationState(element: HTMLElement): \"idle\" | \"running\" | \"paused\" {\n const animations = element.getAnimations();\n if (animations.length === 0) {\n return \"idle\";\n }\n return animations.some((animation) => animation.playState === \"running\")\n ? \"running\"\n : \"paused\";\n },\n\n /**\n * Checks if an element has any active animations\n * @param element - The HTML element to check\n * @returns True if the element has any animations\n * @example\n * ```typescript\n * const element = document.querySelector('.box');\n * if (AnimationUtils.hasAnimations(element)) {\n * console.log('Element has active animations');\n * }\n * ```\n */\n hasAnimations(element: HTMLElement): boolean {\n return element.getAnimations().length > 0;\n },\n\n /**\n * Pauses all animations on an element\n * @param element - The HTML element to pause animations on\n * @example\n * ```typescript\n * const element = document.querySelector('.box');\n * AnimationUtils.pauseAnimations(element);\n * ```\n */\n pauseAnimations(element: HTMLElement): void {\n element.getAnimations().forEach((animation) => animation.pause());\n },\n\n /**\n * Resumes all paused animations on an element\n * @param element - The HTML element to resume animations on\n * @example\n * ```typescript\n * const element = document.querySelector('.box');\n * AnimationUtils.resumeAnimations(element);\n * ```\n */\n resumeAnimations(element: HTMLElement): void {\n element.getAnimations().forEach((animation) => animation.play());\n },\n\n /**\n * Reverses the direction of all animations on an element\n * @param element - The HTML element to reverse animations on\n * @example\n * ```typescript\n * const element = document.querySelector('.box');\n * AnimationUtils.reverseAnimations(element);\n * ```\n */\n reverseAnimations(element: HTMLElement): void {\n element.getAnimations().forEach((animation) => animation.reverse());\n },\n\n /**\n * Stops and removes all animations from an element\n * @param element - The HTML element to stop animations on\n * @example\n * ```typescript\n * const element = document.querySelector('.box');\n * AnimationUtils.stopAnimations(element);\n * ```\n */\n stopAnimations(element: HTMLElement): void {\n element.getAnimations().forEach((animation) => animation.cancel());\n },\n\n /**\n * Waits for all animations on an element to complete\n * @param element - The HTML element to wait for\n * @returns Promise that resolves when all animations complete\n * @example\n * ```typescript\n * const element = document.querySelector('.box');\n * await AnimationUtils.waitForAnimations(element);\n * console.log('All animations completed');\n * ```\n */\n async waitForAnimations(element: HTMLElement): Promise<void> {\n const animations = element.getAnimations();\n await Promise.all(animations.map((animation) => animation.finished));\n },\n};\n"],"names":[],"mappings":"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"}