UNPKG

@zag-js/color-utils

Version:

Color utilities for zag.js

143 lines (141 loc) 4.8 kB
import { __publicField } from "./chunk-QZ7TP4HQ.mjs"; // src/hsb-color.ts import { clampValue, mod, toFixedNumber } from "@zag-js/utils"; import { Color } from "./color.mjs"; import { HSLColor } from "./hsl-color.mjs"; import { RGBColor } from "./rgb-color.mjs"; var HSB_REGEX = /hsb\(([-+]?\d+(?:.\d+)?\s*,\s*[-+]?\d+(?:.\d+)?%\s*,\s*[-+]?\d+(?:.\d+)?%)\)|hsba\(([-+]?\d+(?:.\d+)?\s*,\s*[-+]?\d+(?:.\d+)?%\s*,\s*[-+]?\d+(?:.\d+)?%\s*,\s*[-+]?\d(.\d+)?)\)/; var _HSBColor = class _HSBColor extends Color { constructor(hue, saturation, brightness, alpha) { super(); __publicField(this, "hue", hue); __publicField(this, "saturation", saturation); __publicField(this, "brightness", brightness); __publicField(this, "alpha", alpha); } static parse(value) { let m; if (m = value.match(HSB_REGEX)) { const [h, s, b, a] = (m[1] ?? m[2]).split(",").map((n) => Number(n.trim().replace("%", ""))); return new _HSBColor(mod(h, 360), clampValue(s, 0, 100), clampValue(b, 0, 100), clampValue(a ?? 1, 0, 1)); } } toString(format = "css") { switch (format) { case "css": return this.toHSL().toString("css"); case "hex": return this.toRGB().toString("hex"); case "hexa": return this.toRGB().toString("hexa"); case "hsb": return `hsb(${this.hue}, ${toFixedNumber(this.saturation, 2)}%, ${toFixedNumber(this.brightness, 2)}%)`; case "hsba": return `hsba(${this.hue}, ${toFixedNumber(this.saturation, 2)}%, ${toFixedNumber(this.brightness, 2)}%, ${this.alpha})`; case "hsl": return this.toHSL().toString("hsl"); case "rgb": return this.toRGB().toString("rgb"); default: return this.toFormat(format).toString(format); } } toFormat(format) { switch (format) { case "hsba": return this; case "hsla": return this.toHSL(); case "rgba": return this.toRGB(); default: throw new Error("Unsupported color conversion: hsb -> " + format); } } /** * Converts a HSB color to HSL. * Conversion formula adapted from https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_HSL. * @returns An HSLColor object. */ toHSL() { let saturation = this.saturation / 100; let brightness = this.brightness / 100; let lightness = brightness * (1 - saturation / 2); saturation = lightness === 0 || lightness === 1 ? 0 : (brightness - lightness) / Math.min(lightness, 1 - lightness); return new HSLColor( toFixedNumber(this.hue, 2), toFixedNumber(saturation * 100, 2), toFixedNumber(lightness * 100, 2), toFixedNumber(this.alpha, 2) ); } /** * Converts a HSV color value to RGB. * Conversion formula adapted from https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB_alternative. * @returns An RGBColor object. */ toRGB() { let hue = this.hue; let saturation = this.saturation / 100; let brightness = this.brightness / 100; let fn = (n, k = (n + hue / 60) % 6) => brightness - saturation * brightness * Math.max(Math.min(k, 4 - k, 1), 0); return new RGBColor( Math.round(fn(5) * 255), Math.round(fn(3) * 255), Math.round(fn(1) * 255), toFixedNumber(this.alpha, 2) ); } clone() { return new _HSBColor(this.hue, this.saturation, this.brightness, this.alpha); } getChannelFormatOptions(channel) { switch (channel) { case "hue": return { style: "unit", unit: "degree", unitDisplay: "narrow" }; case "saturation": case "brightness": 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 === "brightness") { 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 "brightness": 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, b: this.brightness, a: this.alpha }; } getFormat() { return "hsba"; } getChannels() { return _HSBColor.colorChannels; } }; __publicField(_HSBColor, "colorChannels", ["hue", "saturation", "brightness"]); var HSBColor = _HSBColor; export { HSBColor };