import getHiddenHeight from './get-hidden-height';
/**
* @module slide
* @description Two simple utils to slide an element up or down from hidden to full height.
*
*/
const options = {
timeoutDelay: 25,
};
const requestIds = [];
const easeFxn = ( t ) =>
t < 0.2074
// eslint-disable-next-line no-mixed-operators
? -3.8716 * t * t * t + 6.137 * t * t + 0.4 * t
// eslint-disable-next-line no-mixed-operators
: 1.1317 * ( t - 1 ) * ( t - 1 ) * ( t - 1 ) -
// eslint-disable-next-line no-mixed-spaces-and-tabs,no-mixed-operators
0.1975 * ( t - 1 ) * ( t - 1 ) +
// eslint-disable-next-line no-mixed-spaces-and-tabs
1;
const checkRequestIds = ( id ) => {
if ( ! requestIds[ id ] ) {
requestIds[ id ] = {
up: null,
down: null,
};
}
};
const cancelAnimations = ( id ) => {
if ( requestIds[ id ].up ) {
window.cancelAnimationFrame( requestIds[ id ].up );
requestIds[ id ].up = null;
}
if ( requestIds[ id ].down ) {
window.cancelAnimationFrame( requestIds[ id ].down );
requestIds[ id ].down = null;
}
};
/**
* @function down
* @description A utility to reveal some hidden content with a slide down animation.
* Element to slide should get the following CSS:
* max-height: 0;
* overflow: hidden;
*
* @since 1.0.0
*
* @param {Node|HTMLElement} elem Element to show.
* @param {string} id Unique ID of animation.
* @param {number} time Length of animation.
* @param {Function} callback Callback function.
*
* @requires getHiddenHeight
*
* @return {void}
*
* @example
* import { slide } from "@gravityforms/utils";
*
* function Example() {
* const target = getNodes( 'example' )[ 0 ];
* const callback = () => {
* //do something after animation
* };
*
* slide.down( target, example, 800, callback );
* }
*
*/
export const down = ( elem, id, time = 400, callback = null ) => {
const startHeight = elem.offsetHeight;
const endHeight = getHiddenHeight( elem );
let startTime = null;
elem.style.maxHeight = '0';
checkRequestIds( id );
cancelAnimations( id );
const step = ( timestamp ) => {
if ( ! startTime ) {
startTime = timestamp;
}
const timeDiff = timestamp - startTime;
const progress = easeFxn( timeDiff / time );
// eslint-disable-next-line no-mixed-operators
const height = progress * ( endHeight - startHeight ) + startHeight;
elem.style.maxHeight = `${ height }px`;
if ( timeDiff < time ) {
requestIds[ id ].down = window.requestAnimationFrame( step );
} else {
requestIds[ id ].down = null;
elem.style.maxHeight = 'none';
if ( callback ) {
callback();
}
}
};
setTimeout( () => {
requestIds[ id ].down = window.requestAnimationFrame( step );
}, options.timeoutDelay );
};
/**
* @function up
* @description A utility to hide some content with a slide up animation.
* Element to slide should get the following CSS:
* max-height: 0;
* overflow: hidden;
*
* @since 1.0.0
*
* @param {Node|HTMLElement} elem Element to hide.
* @param {string} id Unique ID of animation.
* @param {number} time Length of animation.
* @param {Function} callback Callback function.
*
* @requires getHiddenHeight
*
* @return {void}
*
* @example
* import { slide } from "@gravityforms/utils";
*
* function Example() {
* const target = getNodes( 'example' )[ 0 ];
* const callback = () => {
* //do something after animation
* };
*
* slide.up( target, example, 800, callback );
* }
*
*/
export const up = ( elem, id, time = 400, callback = null ) => {
const startHeight = elem.offsetHeight;
const endHeight = 0;
let startTime = null;
elem.style.maxHeight = `${ startHeight }px`;
checkRequestIds( id );
cancelAnimations( id );
const step = ( timestamp ) => {
if ( ! startTime ) {
startTime = timestamp;
}
const timeDiff = timestamp - startTime;
const progress = easeFxn( timeDiff / time );
// eslint-disable-next-line no-mixed-operators
const height = progress * ( endHeight - startHeight ) + startHeight;
elem.style.maxHeight = `${ height }px`;
if ( timeDiff < time ) {
requestIds[ id ].up = window.requestAnimationFrame( step );
} else {
requestIds[ id ].up = null;
elem.style.maxHeight = '0';
if ( callback ) {
callback();
}
}
};
setTimeout( () => {
requestIds[ id ].up = window.requestAnimationFrame( step );
}, options.timeoutDelay );
};