Source: index.js

import Base from 'gradient-base'

/**
 * @typedef {(number[][]|string[])} Colors - colors input 
 */

/**
 * @typedef {object} BaseOptions - Base configuration object
 * @property {string} interpolation - 'linear' or 'bezier'
 * @property {string} [mode] - 'none', 'lch', 'lab', 'rgb', 'hsv', 'hsl', 'hsi', or 'hcl' (only for linear interpolation)
 * @property {number} samples - number of output colors
 * @property {boolean} lightnessCorrection - lightness correction applier
 */

/**
 * @typedef {object} CssOptions - Css configuration object
 * @property {string} type - 'linear' or 'radial'
 * @property {number} [angle] - linear gradient's angle value
 * @property {number} [left] - radial gradient's position on the x axis
 * @property {number} [top] - radial gradient's position on the y axis
 * @property {string} [shape] - radial gradient's shape: 'ellipse' or 'circle' (mandatory for radial gradient)
 * @property {string} [extent] - radial gradient's extent keyword
 */

/**
 * @typedef {object} Options 
 * @property {BaseOptions} base
 * @property {CssOptions} css
 */

/**
 * @class Css
 * @classdesc
 * Css overlay class that returns single gradient strings
 */
export default class Css {
    constructor() {
        /**
         * @property {Base} _base - Base class instance
         * @private
         */
        this._base = new Base()
    }

    /**
     * @returns {string}
     * Returns single css gradient string
     * @param {Colors} colors
     * @param {Options} options
     */
    get(colors, options) {
        this._init(colors, options)
        return `${this.options.css.type}-gradient(${this._angle}${this._shape}${this._extent}${this._stringifyColors()})`
    }

    /**
     * Creates base and options properties
     * @private
     * @returns {void}
     */
    _init(colors, options) {
        this.colors = this._base.get(colors, options.base)
        this.options = options
    }

    /**
     * @returns {string}
     * @private
     */
    get _angle() {
        return this.options.css.angle && this.options.css.type === 'linear' ?
            this.options.css.angle + 'deg, ' :
            ''
    }

    /**
     * @returns {string}
     * @private
     */
    get _shape() {
        if (this.options.css.type === 'radial') {
            if (
                this.options.css.shape &&
                this.options.css.shape !== 'ellipse' &&
                (!this.options.css.top && !this.options.css.left)
            ) {
                return this.options.css.shape + ', '
            }
            if (
                this.options.css.shape &&
                this.options.css.shape !== 'ellipse' &&
                (this.options.css.top && this.options.css.left)
            ) {
                return `${this.options.css.shape} at ${this.options.css.left}% ${this.options.css.top}%, `
            }
            if (
                this.options.css.shape &&
                this.options.css.shape === 'ellipse' &&
                (this.options.css.top && this.options.css.left) &&
                this.options.css.extent === 'none'
            ) {
                return `${this.options.css.shape} at ${this.options.css.left}% ${this.options.css.top}%, `
            }
            if (
                this.options.css.shape &&
                this.options.css.shape === 'ellipse' &&
                (this.options.css.top && this.options.css.left) &&
                this.options.css.extent !== 'none'
            ) {
                return ''
            }
        }
        return ''
    }

    /**
     * @returns {string}
     * @private
     */
    get _extent() {
        const afterExtent = this.options.css.top && this.options.css.left ?
            ` at ${this.options.css.left}% ${this.options.css.top}%, ` :
            ', '
        if (
            this.options.css.shape === 'ellipse' &&
            this.options.css.extent &&
            this.options.css.extent !== 'none'
        ) {
            return this.options.css.extent + afterExtent
        } else if (
            this.options.css.shape === 'ellipse' &&
            !this.options.css.extent &&
            this.options.css.top &&
            this.options.css.left
        ) {
            return afterExtent
        }
        return ''
    }

    /**
     * @returns {string[]}
     * @description
     * Maps rgba arrays to rgba css strings
     * @private
     */
    _stringifyColors() {
        return this.colors.map(color => `rgba(${color[0]}, ${color[1]}, ${color[2]}, ${color[3]})`)
    }
    
}