UNPKG

@gravityforms/utils

Version:
212 lines (200 loc) 8.32 kB
/** * @module animate * @description Animate dom elements using the web animation api. https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API * This set of animations is just a few opinionated animations which currently include things like fading or translateY. * You can either run them on a group, or individually. Configuration can be passed directly, or applied to data attributes on the target element. * Data attributes to be placed on the element if not using the options object are: `data-animation-delay`, `data-animation-duration`, `data-animation-easing`, `data-animation-types`, `data-translate-distance-from`, `data-translate-distance-to`. * * @since 1.5.0 * */ /** * @function getAnimationKeyframes * @description Get the keyframes for the animation. Follows this format https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Keyframe_Formats * * @since 1.5.0 * * @param {HTMLElement} target The target element to animate. * @param {object} options The options for the animation that are needed to form the Keyframe object. * @param {string} options.distanceFrom The distance to travel for translateY if supplied as type. * @param {string} options.distanceTo The distance to travel for translateY if supplied as type. * @param {string} options.opacityFrom The opacity value to animate from for fadeIn or fadeOut types. * @param {string} options.opacityTo The opacity value to animate to for fadeIn or fadeOut types. * @param {string} options.types The types of animations to run. Supports `fadeIn`, `fadeOut`, and `translateY`. You can mix them as space seperated values. * * @return {Array} The Keyframe objects. */ const getAnimationKeyframes = ( target, options ) => { const from = {}; const to = {}; const { distanceFrom = target.dataset?.translateDistanceFrom || '20px', distanceTo = target.dataset?.translateDistanceTo || '0px', opacityFrom = target.dataset?.translateOpacityFrom, opacityTo = target.dataset?.translateOpacityTo, types = target.dataset?.animationTypes || '', } = options; types.split( ' ' ).forEach( ( type ) => { if ( type === 'fadeIn' ) { from.opacity = opacityFrom || 0; to.opacity = opacityTo || 1; } if ( type === 'fadeOut' ) { from.opacity = opacityFrom || 1; to.opacity = opacityTo || 0; } if ( type === 'translateY' ) { from.transform = `translateY(${ distanceFrom })`; to.transform = `translateY(${ distanceTo })`; } } ); return [ from, to ]; }; /** * @function end * @description End the animation. * * @since 1.5.0 * * @param {HTMLElement} target The target element to animate. * @param {object} options The options for the animation that are needed to determine what type of properties are applied to the element at the end of the animation. * @param {string} options.distanceTo The distance to end the translateY animation at if supplied as type. * @param {string} options.opacityTo The opacity value to animate to for fadeIn or fadeOut types. * @param {string} options.types The types of animations to handle. Supports `fadeIn`, `fadeOut`, and `translateY`. */ const end = ( target, options ) => { const { distanceTo = target.dataset?.translateDistanceTo || '0px', opacityTo = target.dataset?.translateOpacityTo, types = target.dataset?.animationTypes || '', } = options; types.split( ' ' ).forEach( ( type ) => { if ( type === 'fadeIn' ) { target.style.opacity = opacityTo || '1'; target.setAttribute( 'aria-hidden', 'false' ); } if ( type === 'fadeOut' ) { target.style.opacity = opacityTo || '0'; target.setAttribute( 'aria-hidden', 'true' ); } if ( type === 'translateY' ) { target.style.transform = `translateY(${ distanceTo })`; } } ); }; /** * @function run * @description Animate a single element. * * @since 1.5.0 * * @param {HTMLElement} target The target element to animate. * @param {object} options The options for the animation that are needed to determine what type of properties are applied to the element at the end of the animation. * @param {Function} options.onAnimateInit Function to run when initializing animation. * @param {Function} options.onAnimateStart Function to run at the beginning of the animation. * @param {Function} options.onAnimateEnd Function to run at the end of the animation. * @param {number} options.delay Delay for the animation in milliseconds. * @param {string|number} options.distance The distance to travel in pixels for translateY if supplied as type. * @param {number} options.duration Duration for the animation in milliseconds. * @param {string} options.easing Easing for the animation. Supports `ease`, `ease-in`, `ease-out`, `ease-in-out`, `linear`, `step-start`, `step-end`, `steps()`, `cubic-bezier()`. * @param {string} options.types The types of animations to run. Supports `fadeIn`, `fadeOut`, and `translateY`. You can mix them as space seperated values. * * @return {void} * @example * import { animate } from '@gravityforms/utils'; * * const animateExample = () => { * const logo = getNode( '.gform-splash__header .gform-logo', document, true ); * * animate.run( logo, { * types: 'fadeIn translateY', * distanceFrom: '-50px', * distanceTo: '0px', * duration: 1000, * easing: 'ease-in-out', * delay: 500, * onInit: () => { * console.log( 'Animation initializing!' ); * }, * onAnimateStart: () => { * console.log( 'Animation starting!' ); * }, * onAnimateEnd: () => { * console.log( 'Animation complete!' ); * }, * } ); * }; * */ const run = ( target = null, options = {} ) => { if ( ! target ) { return; } const { onAnimateInit = () => {}, onAnimateStart = () => {}, onAnimateEnd = () => {}, delay = target.dataset?.animationDelay || 0, duration = target.dataset?.animationDuration || 400, easing = target.dataset?.animationEasing || 'linear', } = options; const keyframes = getAnimationKeyframes( target, options ); onAnimateInit(); setTimeout( () => { onAnimateStart(); requestAnimationFrame( () => { const animated = target.animate( keyframes, { duration: Number( duration ), easing, } ); animated.onfinish = () => { end( target, options ); onAnimateEnd(); }; } ); }, delay ); }; /** * @function runGroup * @description Animate a group of elements. * * @since 1.5.0 * * @param {Array} entries The elements to animate. An array containing a target entry and an options entry that follows the structure of the run function options object. * * @return {void} * @example * import { animate } from '@gravityforms/utils'; * * const animateExample = () => { * const logo = getNode( '.gform-splash__header .gform-logo', document, true ); * const heading = getNode( '.gform-splash__header h1', document, true ); * const text = getNode( '.gform-splash__header p', document, true ); * const button = getNode( '.gform-splash__header .gform-button', document, true ); * const reviews = getNode( '.gform-splash__header .gform-reviews', document, true ); * * const defaults = { * onAnimateEnd: () => { * console.log( `hello from: ${ performance.now() }` ); * }, * distance: -20, * duration: 600, * easing: 'cubic-bezier(0.455, 0.030, 0.515, 0.955)', * types: 'fadeIn translateY', * }; * animate.runGroup( [ * { target: logo, options: { ...defaults } }, * { target: heading, options: { callback: defaults.callback } }, // this one uses data attributes or internal defaults instead since no options where passed here. * { target: text, options: { ...defaults, delay: 200 } }, * { target: button, options: { ...defaults, delay: 300 } }, * { target: reviews, options: { ...defaults, delay: 400 } }, * ] ); * }; * */ const runGroup = ( entries = [] ) => { entries.forEach( ( { target, options } ) => { run( target, options ); } ); }; export { run, runGroup };