sweet.js

import { Spice, Mortar } from './index.js';

/**
 * A Sweetie is a {@link Spice} which can be animated by itself. It is created when calling the method [sweet()]{@linkcode module:paprika-tween/sweet}.
 * @example
import { sweet } from 'paprika-tween';
const { sweetie, spice } = await sweet({
    duration: 2000,
    from: { width: 100 },
    to:   { width: 200 }
    render: (props, interpolation) => { ... }
});
spice.pause();
spice.resume();
await sweetie({
    to:   { width: 0 }
});
spice.dispose();
 * @since 1.0.0
 */
class Sweetie extends Spice {
    constructor(options) {
        super(options);
        this._mortar = new Mortar((time) => this.frame(time));
    }

    start() {
        this._mortar.start();
        super.start(this._mortar.time);
    }
    /**
     * Pauses the animation.
     * @since 1.0.0
     */
    pause() {
        this._mortar.pause();
    }
    /**
     * Resumes the animation.
     * @since 1.0.0
     */
    resume() {
        this._mortar.resume();
    }
    /**
     * Stops the animation, removes its interpolatable properties and its callback functions.
     * @since 1.0.0
     */
    dispose() {
        super.dispose();
        this._mortar.stop();
        this._mortar = null;
    }

    async run(options) {
        return new Promise((resolve) => {
            this.onEnd = function () {
                this.pause();
                resolve({
                    sweetie: this.run.bind(this),
                    spice: this
                });
            };
            if (options) {
                this.from = this.to;
                this.update(options);
            }
            this.start();
        });
    }
    /**
     * Returns whether the instance is running or not.
     * @type {Boolean}
     */
    get running() {
        return this._mortar.running;
    }
}
/**
 * The function <code>sweet()</code> creates a tween animation that will run for the given duration, interpolating the
 * given properties from start to end by using an easing function.<br>
 * <code>sweet()</code> returns a [thenable object]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#thenables}
 * which can be chained with the method [then()]{@linkcode https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then}
 * or awaited with the keyword [await]{@linkcode https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await}
 * to create animations.
 * @param {Object} options
 * @param {number} options.duration - The duration of the interpolation. The time scale should be the same as the
 * starting time and the [frame()]{@linkcode Spice#frame} time.
 * @param {number} [options.delay] - The delay time to start the interpolation.
 * @param {Object} options.from - An object with key/value pairs of numeric properties to interpolate from.
 * @param {Object} options.to - An object with the numeric properties to interpolate to.
 * @param {function} [options.easing] - The easing function with which calculate the value of the property at a given time.
 * You can use your custom function or a function available at [paprika-tween/easing]{@link module:paprika-tween/easing}.
 * Default is <code>Linear.None</code>.
 * @param {function} options.render - A callback function that will be called after each [render]{@linkcode Spice#frame}.
 * It receives two arguments: the first being the amount of interpolation applied from <code>0</code> to <code>1</code>,
 * and the second an object with the properties interpolated for the given time.
 * @param {function} [options.onEnd] - Function called when the interpolation reaches the end. It receive an argument as
 * an object with the properties interpolated to its end values.
 * @returns {Promise} - A Promise that is resolved with two arguments: a <code>sweetie()</code> function to continue with
 * animation, and the {@link Sweetie} instance which properties are interpolated.
 * @module paprika-tween/sweet
 * @function
 * @example
import { sweet } from 'paprika-tween';
const { sweetie, spice } = await sweet({
    duration: 500,
    from: { size: 0 },
    to:   { size: 10 }
    render: ({ size }) => {
        obj.style.borderWidth = `${size}px`;
    }
});
await sweetie({
    duration: 1000,
    to:   { size: 20 }
});
await sweetie({
    to: { size: 1 }
});
await sweetie({
    delay: 50,
    to: { size: 100 }
});
 * @since 1.0.0
 */
export function sweet(options) {
    return new Sweetie(options).run();
}