/**
 * @since Last modified: 2024-07-20 16:07:54
 * @function ease
 * @description Make the hidden element display and gradually expand.
 * @param {object} options  - The parameters of slide down.
 * @param {getEl} [options.elem]  - The target node.The writing is the same as getEl.
 * @param {string} [options.display=block]  - The display of box.Can be filled in:'block'|'flex'|'inline-flex'|'inline-block'|'grid'.
 * @param {curve} [options.curve=easeOut]  - Animation curve.Can be filled in:'linear'|'ease'|'easeIn'|'easeOut'|'easeInOut'|'easeOutIn'.
 * @param {boolean} [options.cut=true]  - Forced overflow truncation,means to add the style attribute of the element:"overflow:hidden".
 * @param {number} [options.duration=500]  - The duration of slide down.The unit is ms.The default is automatically calculated by the element height.
 * @param {fn_cb_ease_base} [options.doing]  - The call back in progress.Support parameters:"frame" and "step",That is the current animation frame and height.
 * @param {fn_cb_ease_base} [options.done]  - The call back after completion.Support parameters:"frame" and "step",That is the current animation frame and height(orign height).
 * @returns {*} - The the target dom.
 * @see {@link https://codepen.io/axui/pen/eYxXMOG|demo @ codepen}
 * @example
 * ax.ease({elem:'#demo',from:{width:0,height:0},to:{width:100,height:100}});
 * <!--return the target dom-->
 */
'use strict';
import curveFns from "./curveFns";
import ax from "../ax";
import { T_obj } from "../../../types/ax";
type Options = { from: T_obj, to: T_obj, before?: Function, doing?: Function, done?: Function, curve?: 'linear'|'ease'|'easeIn'|'easeOut'|'easeInOut'|'easeOutIn', duration?: number }
let ease = ({ from, to, before, doing, done, duration, curve }: Options) => {
    /**
    * @callback fn_cb_ease_base
    * @description The call back after ease.
    * @param {string} frame - The current animation frame of screen.
    * @param {object} value - The current value of properties,it may be the height,width,opacity and so on.
    * @param {number} step - The ease progress,The range is:[0,1].
    * @returns null.
    */
    if (!from || !to) throw new Error('from and to are required!');
    before && before();
    let initTime = new Date().getTime(),
        result = { step: 0, value: {}, frame: 0 },
        repeat = () => {
            let newTime = new Date().getTime() - initTime,
                ratio = newTime / (duration || 500),
                step = curveFns[curve || 'easeOut'](ratio),
                value = { ...from },
                frame = requestAnimationFrame(repeat);
            for (let k in from) {
                from.hasOwnProperty(k) && from[k] !== to[k] ? value[k] = from[k] + (to[k] - from[k]) * step : null;
            }
            result = { step, frame, value };
            if (ratio < 1) {
                doing && doing(result);
            } else {
                cancelAnimationFrame(frame);
                result.step = 1;
                result.value = { ...to };
                done && done(result);
            }
            ax.frame = frame;
        };
    repeat();
    return result;
};
export default ease;
