UNPKG

tiny-essentials

Version:

Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.

521 lines (520 loc) 16.3 kB
/** * Represents a color in RGBA format. * Each element must be a number between 0 and 255. * The fourth value represents the alpha (transparency) channel. * * @typedef {number[]} RgbaColor * @property {number} 0 - Red component (0–255) * @property {number} 1 - Green component (0–255) * @property {number} 2 - Blue component (0–255) * @property {number} 3 - Alpha component (0–255) */ /** * Represents a color in RGB format. * Each element must be a number between 0 and 255. * * @typedef {number[]} RgbColor * @property {number} 0 - Red component (0–255) * @property {number} 1 - Green component (0–255) * @property {number} 2 - Blue component (0–255) */ /** * Represents a color in HSLA format. * The fourth value represents the alpha (transparency) channel. * * @typedef {number[]} HslaColor * @property {number} 0 - Hue (0–360) * @property {number} 1 - Saturation (0–100) * @property {number} 2 - Lightness (0–100) * @property {number} 3 - Alpha component (0–255) */ /** * Represents a color in HSL format. * * @typedef {number[]} HslColor * @property {number} 0 - Hue (0–360) * @property {number} 1 - Saturation (0–100) * @property {number} 2 - Lightness (0–100) */ /** * Represents a hex color. * * @typedef {string} HexColor */ /** * A union type representing various accepted color formats. * Can be a hex color string, a numeric value, or an array-based RGB/RGBA representation. * * @typedef {HexColor | number | RgbColor | RgbaColor} ColorTypes */ /** * @typedef {Object} RgbaResult * @property {number} r - Red component (0–255) * @property {number} g - Green component (0–255) * @property {number} b - Blue component (0–255) * @property {number} a - Alpha component (0–255) */ /** * @typedef {Object} RgbResult * @property {number} r - Red component (0–255) * @property {number} g - Green component (0–255) * @property {number} b - Blue component (0–255) */ /** * @typedef {Object} HexResult * @property {string} hex - Hex color */ /** * @typedef {Object} HslResult * @property {number} h - Hue (0–360) * @property {number} s - Saturation (0–100) * @property {number} l - Lightness (0–100) */ /** * A class that allows converting colors between all common formats. */ class TinyColorConverter { /** * Generates a smooth gradient of colors based on sine wave patterns. * * @see {@link https://www.npmjs.com/package/rainbow-colors-array} Code Reference * @param {number} [len=24] - The number of colors to generate. * @param {'rgb'|'hex'|'hsl'} [type='rgb'] - The format of the colors returned: `'rgb'`, `'hex'`, or `'hsl'`. * @param {boolean} [pastel=false] - If true, generates pastel tones by adjusting the intensity and offset. * @returns {Array<RgbResult|HexResult|HslResult>} An array of color values in the selected format: */ static _rca(len, type, pastel) { let eq1 = 127; let eq2 = 128; if (len === undefined) { len = 24; } if (type === undefined) { type = 'rgb'; } if (pastel === true) { eq1 = 55; eq2 = 200; } const frequency = (Math.PI * 2) / len; const cvparr = []; for (let i = 0; i < len; ++i) { const red = Math.sin(frequency * i + 2) * eq1 + eq2; const green = Math.sin(frequency * i + 0) * eq1 + eq2; const blue = Math.sin(frequency * i + 4) * eq1 + eq2; switch (type) { case 'hex': cvparr.push({ hex: this.rgbToHex(Math.round(red), Math.round(green), Math.round(blue)) }); break; case 'rgb': cvparr.push({ r: red, g: green, b: blue }); break; case 'hsl': const [h, s, l] = this.rgbaToHsl(Math.round(red), Math.round(green), Math.round(blue)); cvparr.push({ h, s, l }); break; } } return cvparr; } /** * Generates a smooth gradient of colors based on sine wave patterns. * * @param {number} [len=24] - The number of colors to generate. * @param {boolean} [pastel=false] - If true, generates pastel tones by adjusting the intensity and offset. * @returns {RgbResult[]} An array of rgb color values. */ static rcaRgb(len, pastel) { return /** @type {RgbResult[]} */ (TinyColorConverter._rca(len, 'rgb', pastel)); } /** * Generates a smooth gradient of colors based on sine wave patterns. * * @param {number} [len=24] - The number of colors to generate. * @param {boolean} [pastel=false] - If true, generates pastel tones by adjusting the intensity and offset. * @returns {HslResult[]} An array of hsl color values. */ static rcaHsl(len, pastel) { return /** @type {HslResult[]} */ (TinyColorConverter._rca(len, 'hsl', pastel)); } /** * Generates a smooth gradient of colors based on sine wave patterns. * * @param {number} [len=24] - The number of colors to generate. * @param {boolean} [pastel=false] - If true, generates pastel tones by adjusting the intensity and offset. * @returns {HexResult[]} An array of hex color values. */ static rcaHex(len, pastel) { return /** @type {HexResult[]} */ (TinyColorConverter._rca(len, 'hex', pastel)); } /** * Generates a random color in hexadecimal format. * * @returns {HexColor} A hex color string (e.g. `#a3e5f2`). */ static randomColor() { const hex = Math.floor(Math.random() * 0x1000000).toString(16); return `#${hex.padStart(6, '0')}`; } /** * Parses input into RGBA array. * @param {ColorTypes} input * @param {boolean} isHsl * @returns {RgbaColor} */ static parseInput(input, isHsl) { if (typeof input === 'string') { input = input.trim().toLowerCase(); if (input.startsWith('#')) return this.hexToRgba(input); if (input.startsWith('rgb')) return this.rgbStringToRgbaArray(input); if (input.startsWith('hsl')) return this.hslStringToRgbaArray(input); } if (typeof input === 'number') return this.intToRgba(input); if (Array.isArray(input) && (input.length === 3 || input.length === 4) && input.every((item) => typeof item === 'number')) { if (isHsl) { const [h, s, l, a2] = input; if (h <= 360 && s <= 100 && l <= 100) return this.hslToRgba(h, s, l, a2); } return [...input, 1].slice(0, 4); } throw new Error('Unsupported color format.'); } // HSL Color /** * Converts hsl to integer. * @param {number} h - Hue (0–360) * @param {number} s - Saturation (0–100) * @param {number} l - Lightness (0–100) * @returns {number} */ static hslToInt(h, s, l) { const [r, g, b] = TinyColorConverter.hslToRgba(h, s, l); return TinyColorConverter.rgbToInt(r, g, b); } /** * Converts hsl to hex. * @param {number} h - Hue (0–360) * @param {number} s - Saturation (0–100) * @param {number} l - Lightness (0–100) * @returns {HexColor} */ static hslToHex(h, s, l) { const [r, g, b] = TinyColorConverter.hslToRgba(h, s, l); return TinyColorConverter.rgbToHex(r, g, b); } /** * Converts hsl(a) string to RGBA array. * @param {string} hsl * @returns {RgbaColor} */ static hslStringToRgbaArray(hsl) { const match = hsl.match(/[\d.]+/g)?.map(Number); if (!match || match.length < 3) return [0, 0, 0, 1]; const [h, s, l, a = 1] = match; return this.hslToRgba(h, s, l, a); } /** * Converts HSL or HSLA to RGBA. * @param {number} h - Hue (0–360) * @param {number} s - Saturation (0–100) * @param {number} l - Lightness (0–100) * @param {number} [a=1] - Alpha (0–1) * @returns {RgbaColor} */ static hslToRgba(h, s, l, a = 1) { s /= 100; l /= 100; /** @type {(n: number) => number} */ const k = (n) => (n + h / 30) % 12; const a_ = s * Math.min(l, 1 - l); /** @type {(n: number) => number} */ const f = (n) => l - a_ * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1))); return [Math.round(f(0) * 255), Math.round(f(8) * 255), Math.round(f(4) * 255), a]; } /** * Converts HSL or HSLA to RGB. * @param {number} h - Hue (0–360) * @param {number} s - Saturation (0–100) * @param {number} l - Lightness (0–100) * @param {number} [a=1] - Alpha (0–1) * @returns {RgbColor} */ static hslToRgb(h, s, l, a = 1) { return TinyColorConverter.hslToRgba(h, s, l, a).slice(0, 3); } // Hex Color /** * Converts hex to integer. * @param {HexColor} hex * @returns {number} */ static hexToInt(hex) { return parseInt(hex.replace(/^#/, ''), 16); } /** * Converts hex string to HSL array. * @param {HexColor} hex * @returns {HslColor} */ static hexToHsl(hex) { const [r, g, b, a] = TinyColorConverter.hexToRgba(hex); return TinyColorConverter.rgbaToHsl(r, g, b, a); } /** * Converts hex string to HSL array. * @param {HexColor} hex * @returns {HslaColor} */ static hexToHsla(hex) { const [r, g, b, a] = TinyColorConverter.hexToRgba(hex); return TinyColorConverter.rgbaToHsla(r, g, b, a); } /** * Converts hex string to RGBA array. * @param {HexColor} hex * @returns {RgbaColor} */ static hexToRgba(hex) { hex = hex.replace(/^#/, ''); if (hex.length === 3) hex = hex .split('') .map((c) => c + c) .join(''); const intVal = parseInt(hex, 16); const r = (intVal >> 16) & 255; const g = (intVal >> 8) & 255; const b = intVal & 255; return [r, g, b, 1]; } /** * Converts HEX to RGB. * @param {HexColor} hex * @returns {RgbColor} */ static hexToRgb(hex) { return this.hexToRgba(hex).slice(0, 3); } // RGBA Color /** * Converts RGB to HEX. * @param {number} r * @param {number} g * @param {number} b * @returns {HexColor} */ static rgbToHex(r, g, b) { return '#' + [r, g, b].map((v) => v.toString(16).padStart(2, '0')).join(''); } /** * Converts RGB to integer. * @param {number} r * @param {number} g * @param {number} b * @returns {number} */ static rgbToInt(r, g, b) { return (r << 16) | (g << 8) | b; } /** * Converts RGBA to HSLA. * @param {number} r * @param {number} g * @param {number} b * @param {number} [a=1] * @returns {HslaColor} */ static rgbaToHsla(r, g, b, a = 1) { r /= 255; g /= 255; b /= 255; const max = Math.max(r, g, b); const min = Math.min(r, g, b); let h = 0, s = 0, l = (max + min) / 2; const d = max - min; if (d !== 0) { s = d / (1 - Math.abs(2 * l - 1)); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h *= 60; } return [Math.round(h), Math.round(s * 100), Math.round(l * 100), a]; } /** * Converts RGBA to HSL. * @param {number} r * @param {number} g * @param {number} b * @param {number} [a=1] * @returns {HslColor} */ static rgbaToHsl(r, g, b, a) { return this.rgbaToHsla(r, g, b, a).slice(0, 3); } /** * Converts rgb(a) string to RGBA array. * @param {string} rgb * @returns {RgbaColor} */ static rgbStringToRgbaArray(rgb) { const match = rgb.match(/[\d.]+/g)?.map(Number); if (!match) return []; return [...match, 1].slice(0, 4); } // Integer Color /** * Converts integer color to HSL. * @param {number} int * @returns {HslColor} */ static intToHsl(int) { const [r, g, b, a] = TinyColorConverter.intToRgba(int); return TinyColorConverter.rgbaToHsl(r, g, b, a); } /** * Converts integer color to HSL. * @param {number} int * @returns {HslaColor} */ static intToHsla(int) { const [r, g, b, a] = TinyColorConverter.intToRgba(int); return TinyColorConverter.rgbaToHsla(r, g, b, a); } /** * Converts integer color to hex. * @param {number} int * @returns {HexColor} */ static intToHex(int) { return '#' + int.toString(16).padStart(6, '0'); } /** * Converts an integer (0xRRGGBB) to RGBA. * @param {number} value * @returns {RgbaColor} */ static intToRgba(value) { const r = (value >> 16) & 255; const g = (value >> 8) & 255; const b = value & 255; return [r, g, b, 1]; } // Class Script /** @type {ColorTypes} */ #original = '#000000'; /** @type {RgbaColor} */ #rgba = [0, 0, 0, 0]; #checkIsHsl; /** * @param {ColorTypes|null} [input=null] - Any valid color (hex, rgb string, rgba string, hsl(a), css name, array or int). * @param {boolean} [checkIsHsl=false] */ constructor(input = null, checkIsHsl = false) { this.#checkIsHsl = checkIsHsl; if (typeof input !== 'undefined' && input !== null) this.setColor(input); } /** * @param {ColorTypes} input - Any valid color (hex, rgb string, rgba string, hsl(a), css name, array or int). */ setColor(input) { this.#original = input; const isHsl = this.#checkIsHsl && Array.isArray(input) && input[0] <= 360 && input[1] <= 100 && input[2] <= 100; this.#rgba = TinyColorConverter.parseInput(input, isHsl); } /** * Returns HSLA array. * @returns {HslaColor} */ toHslaArray() { const [r, g, b, a] = this.#rgba; return TinyColorConverter.rgbaToHsla(r, g, b, a); } /** * Returns RGB string. * @returns {string} */ toHslString() { const [r, g, b] = this.#rgba; const [h, s, l] = TinyColorConverter.rgbaToHsl(r, g, b); return `hsl(${h}, ${s}%, ${l}%)`; } /** * Returns RGBA string. * @returns {string} */ toHslaString() { const [r, g, b, a] = this.#rgba; const [h, s, l, a2] = TinyColorConverter.rgbaToHsla(r, g, b, a); return `hsla(${h}, ${s}%, ${l}%, ${a2 ?? 1})`; } /** * Returns RGBA array. * @returns {RgbaColor} */ toRgbaArray() { return [...this.#rgba]; } /** * Returns RGB string. * @returns {string} */ toRgbString() { const [r, g, b] = this.#rgba; return `rgb(${r}, ${g}, ${b})`; } /** * Returns RGBA string. * @returns {string} */ toRgbaString() { const [r, g, b, a] = this.#rgba; return `rgba(${r}, ${g}, ${b}, ${a ?? 1})`; } /** * Returns hex color. * @returns {HexColor} */ toHex() { const [r, g, b] = this.#rgba; return TinyColorConverter.rgbToHex(r, g, b); } /** * Returns color as integer. * @returns {number} */ toInt() { const [r, g, b] = this.#rgba; return TinyColorConverter.rgbToInt(r, g, b); } /** * Returns the original input. * @returns {ColorTypes} */ getOriginal() { return this.#original; } } export default TinyColorConverter;