UNPKG

@zag-js/color-utils

Version:

Color utilities for zag.js

144 lines (142 loc) 4.78 kB
import { __publicField } from "./chunk-QZ7TP4HQ.mjs"; // src/hsl-color.ts import { clampValue, mod, toFixedNumber } from "@zag-js/utils"; import { Color } from "./color.mjs"; import { HSBColor } from "./hsb-color.mjs"; import { RGBColor } from "./rgb-color.mjs"; var HSL_REGEX = /hsl\(([-+]?\d+(?:.\d+)?\s*,\s*[-+]?\d+(?:.\d+)?%\s*,\s*[-+]?\d+(?:.\d+)?%)\)|hsla\(([-+]?\d+(?:.\d+)?\s*,\s*[-+]?\d+(?:.\d+)?%\s*,\s*[-+]?\d+(?:.\d+)?%\s*,\s*[-+]?\d(.\d+)?)\)/; var _HSLColor = class _HSLColor extends Color { constructor(hue, saturation, lightness, alpha) { super(); __publicField(this, "hue", hue); __publicField(this, "saturation", saturation); __publicField(this, "lightness", lightness); __publicField(this, "alpha", alpha); } static parse(value) { let m; if (m = value.match(HSL_REGEX)) { const [h, s, l, a] = (m[1] ?? m[2]).split(",").map((n) => Number(n.trim().replace("%", ""))); return new _HSLColor(mod(h, 360), clampValue(s, 0, 100), clampValue(l, 0, 100), clampValue(a ?? 1, 0, 1)); } } toString(format = "css") { switch (format) { case "hex": return this.toRGB().toString("hex"); case "hexa": return this.toRGB().toString("hexa"); case "hsl": return `hsl(${this.hue}, ${toFixedNumber(this.saturation, 2)}%, ${toFixedNumber(this.lightness, 2)}%)`; case "css": case "hsla": return `hsla(${this.hue}, ${toFixedNumber(this.saturation, 2)}%, ${toFixedNumber(this.lightness, 2)}%, ${this.alpha})`; case "hsb": return this.toHSB().toString("hsb"); case "rgb": return this.toRGB().toString("rgb"); default: return this.toFormat(format).toString(format); } } toFormat(format) { switch (format) { case "hsla": return this; case "hsba": return this.toHSB(); case "rgba": return this.toRGB(); default: throw new Error("Unsupported color conversion: hsl -> " + format); } } /** * Converts a HSL color to HSB. * Conversion formula adapted from https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_HSV. * @returns An HSBColor object. */ toHSB() { let saturation = this.saturation / 100; let lightness = this.lightness / 100; let brightness = lightness + saturation * Math.min(lightness, 1 - lightness); saturation = brightness === 0 ? 0 : 2 * (1 - lightness / brightness); return new HSBColor( toFixedNumber(this.hue, 2), toFixedNumber(saturation * 100, 2), toFixedNumber(brightness * 100, 2), toFixedNumber(this.alpha, 2) ); } /** * Converts a HSL color to RGB. * Conversion formula adapted from https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB_alternative. * @returns An RGBColor object. */ toRGB() { let hue = this.hue; let saturation = this.saturation / 100; let lightness = this.lightness / 100; let a = saturation * Math.min(lightness, 1 - lightness); let fn = (n, k = (n + hue / 30) % 12) => lightness - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); return new RGBColor( Math.round(fn(0) * 255), Math.round(fn(8) * 255), Math.round(fn(4) * 255), toFixedNumber(this.alpha, 2) ); } clone() { return new _HSLColor(this.hue, this.saturation, this.lightness, this.alpha); } getChannelFormatOptions(channel) { switch (channel) { case "hue": return { style: "unit", unit: "degree", unitDisplay: "narrow" }; case "saturation": case "lightness": case "alpha": return { style: "percent" }; default: throw new Error("Unknown color channel: " + channel); } } formatChannelValue(channel, locale) { let options = this.getChannelFormatOptions(channel); let value = this.getChannelValue(channel); if (channel === "saturation" || channel === "lightness") { value /= 100; } return new Intl.NumberFormat(locale, options).format(value); } getChannelRange(channel) { switch (channel) { case "hue": return { minValue: 0, maxValue: 360, step: 1, pageSize: 15 }; case "saturation": case "lightness": return { minValue: 0, maxValue: 100, step: 1, pageSize: 10 }; case "alpha": return { minValue: 0, maxValue: 1, step: 0.01, pageSize: 0.1 }; default: throw new Error("Unknown color channel: " + channel); } } toJSON() { return { h: this.hue, s: this.saturation, l: this.lightness, a: this.alpha }; } getFormat() { return "hsla"; } getChannels() { return _HSLColor.colorChannels; } }; __publicField(_HSLColor, "colorChannels", ["hue", "saturation", "lightness"]); var HSLColor = _HSLColor; export { HSLColor, HSL_REGEX };