{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "native-utils", "type": "registry:lib", "title": "Native Utils", "description": "Native Utils from @pitsi-ui/native for native projects.", "dependencies": [ "tailwind-variants@^3.2.2" ], "registryDependencies": [], "files": [ { "path": "registry/native-ui/src/helpers/external/utils/cn.ts", "content": "import { type CnOptions, cnMerge } from \"tailwind-variants\";\n\nexport function cn(...args: CnOptions) {\n return cnMerge(args)({\n twMerge: true,\n twMergeConfig: {\n classGroups: {\n opacity: [{ opacity: [\"disabled\"] }],\n },\n },\n });\n}\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/external/utils/cn.ts" }, { "path": "registry/native-ui/src/helpers/external/utils/color-kit/index.ts", "content": "/**\n * Color manipulation utilities adapted from reanimated-color-picker\n *\n * Original source: https://github.com/alabsi91/reanimated-color-picker\n * Author: @alabsi91\n * License: MIT\n *\n * This code has been adapted for use in PitsiUI Native with modifications\n * for TypeScript compatibility and integration with the theme system.\n */\n\nimport type {\n ColorFormats,\n ColorTypes,\n ConversionMethods,\n hslaT,\n hslT,\n hsvaT,\n hsvT,\n hwbaT,\n hwbT,\n rgbaT,\n rgbT,\n SupportedColorFormats,\n} from \"./types\";\n\n// If you find yourself wondering why all of this is within a single function,\n// the reason is that to execute each method on the UI thread, you must include the 'worklet' directive.\n// Functions marked with this directive are transformed by the Reanimated Babel plugin\n// into IIFE — IMMEDIATELY INVOKED FUNCTION EXPRESSION: `const fun = (function{})()`.\n// Due to the presence of numerous methods,\n// this transformation can lead to a slow initial execution.\n// To address this issue, I consolidated them into a single worklet function.\n\nexport const colorKitUI = () => {\n \"worklet\";\n\n const NAMED_COLORS = {\n aliceblue: \"#f0f8ff\",\n antiquewhite: \"#faebd7\",\n aqua: \"#00ffff\",\n aquamarine: \"#7fffd4\",\n azure: \"#f0ffff\",\n beige: \"#f5f5dc\",\n bisque: \"#ffe4c4\",\n black: \"#000000\",\n blanchedalmond: \"#ffebcd\",\n blue: \"#0000ff\",\n blueviolet: \"#8a2be2\",\n brown: \"#a52a2a\",\n burlywood: \"#deb887\",\n cadetblue: \"#5f9ea0\",\n chartreuse: \"#7fff00\",\n chocolate: \"#d2691e\",\n coral: \"#ff7f50\",\n cornflowerblue: \"#6495ed\",\n cornsilk: \"#fff8dc\",\n crimson: \"#dc143c\",\n cyan: \"#00ffff\",\n darkblue: \"#00008b\",\n darkcyan: \"#008b8b\",\n darkgoldenrod: \"#b8860b\",\n darkgray: \"#a9a9a9\",\n darkgreen: \"#006400\",\n darkgrey: \"#a9a9a9\",\n darkkhaki: \"#bdb76b\",\n darkmagenta: \"#8b008b\",\n darkolivegreen: \"#556b2f\",\n darkorange: \"#ff8c00\",\n darkorchid: \"#9932cc\",\n darkred: \"#8b0000\",\n darksalmon: \"#e9967a\",\n darkseagreen: \"#8fbc8f\",\n darkslateblue: \"#483d8b\",\n darkslategrey: \"#2f4f4f\",\n darkturquoise: \"#00ced1\",\n darkviolet: \"#9400d3\",\n deeppink: \"#ff1493\",\n deepskyblue: \"#00bfff\",\n dimgray: \"#696969\",\n dimgrey: \"#696969\",\n dodgerblue: \"#1e90ff\",\n firebrick: \"#b22222\",\n floralwhite: \"#fffaf0\",\n forestgreen: \"#228b22\",\n fuchsia: \"#ff00ff\",\n gainsboro: \"#dcdcdc\",\n ghostwhite: \"#f8f8ff\",\n gold: \"#ffd700\",\n goldenrod: \"#daa520\",\n gray: \"#808080\",\n green: \"#008000\",\n greenyellow: \"#adff2f\",\n grey: \"#808080\",\n honeydew: \"#f0fff0\",\n hotpink: \"#ff69b4\",\n indianred: \"#cd5c5c\",\n indigo: \"#4b0082\",\n ivory: \"#fffff0\",\n khaki: \"#f0e68c\",\n lavender: \"#e6e6fa\",\n lavenderblush: \"#fff0f5\",\n lawngreen: \"#7cfc00\",\n lemonchiffon: \"#fffacd\",\n lightblue: \"#add8e6\",\n lightcoral: \"#f08080\",\n lightcyan: \"#e0ffff\",\n lightgoldenrodyellow: \"#fafad2\",\n lightgray: \"#d3d3d3\",\n lightgreen: \"#90ee90\",\n lightgrey: \"#d3d3d3\",\n lightpink: \"#ffb6c1\",\n lightsalmon: \"#ffa07a\",\n lightseagreen: \"#20b2aa\",\n lightskyblue: \"#87cefa\",\n lightslategrey: \"#778899\",\n lightsteelblue: \"#b0c4de\",\n lightyellow: \"#ffffe0\",\n lime: \"#00ff00\",\n limegreen: \"#32cd32\",\n linen: \"#faf0e6\",\n magenta: \"#ff00ff\",\n maroon: \"#800000\",\n mediumaquamarine: \"#66cdaa\",\n mediumblue: \"#0000cd\",\n mediumorchid: \"#ba55d3\",\n mediumpurple: \"#9370db\",\n mediumseagreen: \"#3cb371\",\n mediumslateblue: \"#7b68ee\",\n mediumspringgreen: \"#00fa9a\",\n mediumturquoise: \"#48d1cc\",\n mediumvioletred: \"#c71585\",\n midnightblue: \"#191970\",\n mintcream: \"#f5fffa\",\n mistyrose: \"#ffe4e1\",\n moccasin: \"#ffe4b5\",\n navajowhite: \"#ffdead\",\n navy: \"#000080\",\n oldlace: \"#fdf5e6\",\n olive: \"#808000\",\n olivedrab: \"#6b8e23\",\n orange: \"#ffa500\",\n orangered: \"#ff4500\",\n orchid: \"#da70d6\",\n palegoldenrod: \"#eee8aa\",\n palegreen: \"#98fb98\",\n paleturquoise: \"#afeeee\",\n palevioletred: \"#db7093\",\n papayawhip: \"#ffefd5\",\n peachpuff: \"#ffdab9\",\n peru: \"#cd853f\",\n pink: \"#ffc0cb\",\n plum: \"#dda0dd\",\n powderblue: \"#b0e0e6\",\n purple: \"#800080\",\n rebeccapurple: \"#663399\",\n red: \"#ff0000\",\n rosybrown: \"#bc8f8f\",\n royalblue: \"#4169e1\",\n saddlebrown: \"#8b4513\",\n salmon: \"#fa8072\",\n sandybrown: \"#f4a460\",\n seagreen: \"#2e8b57\",\n seashell: \"#fff5ee\",\n sienna: \"#a0522d\",\n silver: \"#c0c0c0\",\n skyblue: \"#87ceeb\",\n slateblue: \"#6a5acd\",\n slategray: \"#708090\",\n snow: \"#fffafa\",\n springgreen: \"#00ff7f\",\n steelblue: \"#4682b4\",\n tan: \"#d2b48c\",\n teal: \"#008080\",\n thistle: \"#d8bfd8\",\n tomato: \"#ff6347\",\n turquoise: \"#40e0d0\",\n violet: \"#ee82ee\",\n wheat: \"#f5deb3\",\n white: \"#ffffff\",\n whitesmoke: \"#f5f5f5\",\n yellow: \"#ffff00\",\n yellowgreen: \"#9acd32\",\n };\n\n const COLORS_REGEX: Record = {\n // #rgb\n hex3: /^#([A-Fa-f0-9]{3})$/,\n // #rgba\n hex4: /^#([A-Fa-f0-9]{3}[A-Fa-f0-9]{1})$/,\n // #rrggbb\n hex6: /^#([A-Fa-f0-9]{6})$/,\n // #rrggbbaa\n hex8: /^#([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i,\n\n hsl: [\n // hsl(360deg, 100%, 100%) hsl(360, 100%, 100%) hsl(23.55, 12.22%, 34.56%)\n /^hsl\\s*\\(\\s*([\\d.]+)(?:deg)?\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%\\s*\\)$/i,\n // hsl(360deg 100% 100%) hsl(360 100% 100%) hsl(23.55 12.22% 34.56%)\n /^hsl\\s*\\(\\s*([\\d.]+)(?:deg)?\\s+([\\d.]+)%\\s+([\\d.]+)%\\s*\\)$/i,\n ],\n hsla: [\n // hsla(360deg, 100%, 100%, 1.0) hsla(360, 100%, 100%, 1.0) hsl(360deg, 100%, 100%, 1.0) hsl(360, 100%, 100%, 1.0)\n /^hsla?\\s*\\(\\s*([\\d.]+)(?:deg)?\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%\\s*,\\s*(\\d|\\d\\.\\d+)\\s*\\)$/i,\n // hsla(360deg 100% 100% / 1.0) hsla(360 100% 100% / 1.0) hsl(360deg 100% 100% / 1.0) hsl(360 100% 100% / 1.0)\n /^hsla?\\s*\\(\\s*([\\d.]+)(?:deg)?\\s+([\\d.]+)%\\s+([\\d.]+)%\\s*\\/\\s*(\\d|\\d\\.\\d+)\\s*\\)$/i,\n ],\n\n hsv: [\n // hsv(360deg, 000%, 000%) hsv(360, 100%, 100%)\n /^hsv\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%\\s*\\)$/i,\n // hsv(360deg 000% 000%) hsv(360 100% 100%)\n /^hsv\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s+([\\d.]+)%\\s+([\\d.]+)%\\s*\\)$/i,\n ],\n hsva: [\n // hsva(360deg, 100%, 100%, 1.0) hsva(360, 100%, 100%, 1.0) hsv(360deg, 100%, 100%, 1.0) hsv(360, 100%, 100%, 1.0)\n /^hsva?\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%\\s*,\\s*(\\d|\\d\\.\\d+)\\s*\\)$/i,\n // hsva(360deg 100% 100% / 1.0) hsva(360 100% 100% / 1.0) hsv(360deg 100% 100% / 1.0) hsv(360 100% 100% / 1.0)\n /^hsva?\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s+([\\d.]+)%\\s+([\\d.]+)%\\s*\\/\\s*(\\d|\\d\\.\\d+)\\s*\\)$/i,\n ],\n\n hwb: [\n // hwb(360deg, 100%, 100%) hwb(360, 100%, 100%)\n /^hwb\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%\\s*\\)$/i,\n // hwb(360deg 100% 100%) hwb(360 100% 100%)\n /^hwb\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s+([\\d.]+)%\\s+([\\d.]+)%\\s*\\)$/i,\n ],\n hwba: [\n // hwba(360deg, 100%, 100%, 1.0) hwba(360, 100%, 100%, 1.0) hwb(360deg, 100%, 100%, 1.0) hwb(360, 100%, 100%, 1.0)\n /^hwba?\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%\\s*,\\s*(\\d|\\d\\.\\d+)\\s*\\)$/i,\n // hwb(360deg 100% 100% 1.0) hwb(360 100% 100% / 1.0) hwba(360deg 100% 100% 1.0) hwba(360 100% 100% / 1.0)\n /^hwba?\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s+([\\d.]+)%\\s+([\\d.]+)%\\s*\\/\\s*(\\d|\\d\\.\\d+)\\s*\\)$/i,\n ],\n\n rgb: [\n // rgb(255, 255, 255)\n /^rgb\\s*\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*\\)$/i,\n // rgb(255 255 255)\n /^rgb\\s*\\(\\s*(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s*\\)$/i,\n ],\n rgba: [\n // rgba(255, 255, 255, 1.0) rgb(255, 255, 255, 1.0)\n /^rgba?\\s*\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*([\\d.]+)\\s*\\)$/i,\n // rgba(255 255 255 / 1.0) rgb(255 255 255 / 1.0)\n /^rgba?\\s*\\(\\s*(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s*\\/\\s*([\\d.]+)\\s*\\)$/i,\n ],\n };\n\n // * MARK: General utilities\n\n const clamp = (value: number, min: number, max: number) => {\n return Math.max(min, Math.min(value, max));\n };\n\n const clampRGB = (value: number) => {\n return clamp(value, 0, 255);\n };\n\n const clampHue = (value: number) => {\n return clamp(value, 0, 360);\n };\n\n const clamp100 = (value: number) => {\n return clamp(value, 0, 100);\n };\n\n const clampAlpha = (value: number) => {\n return clamp(+value.toFixed(2), 0, 1);\n };\n\n const randomNumber = (min: number, max: number) => {\n return Math.random() * (max - min) + min;\n };\n\n const numberToHexString = (c: number): string => {\n c = clampRGB(Math.round(c));\n const hex = c.toString(16).padStart(2, \"0\");\n return hex;\n };\n\n const calculateHueValue = (p: number, q: number, t: number): number => {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n };\n\n /** - Identify the color format of a given `string` or `object` */\n const detectColorFormat = (color: SupportedColorFormats): ColorFormats | null => {\n // color int\n if (typeof color === \"number\") {\n // eslint-disable-next-line no-bitwise\n if (color >>> 0 === color && color >= 0 && color <= 0xffffffff) return \"hex8\";\n return null;\n }\n\n // color string\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n for (const key in COLORS_REGEX) {\n const format = key as ColorFormats;\n const entry = COLORS_REGEX[format];\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(color)) return format;\n }\n continue;\n }\n if (entry.test(color)) return format;\n }\n }\n\n // color object\n if (typeof color === \"object\") {\n const rgbaKeys = [\"r\", \"g\", \"b\", \"a\"] as (keyof rgbaT)[];\n const isRgbaOb = rgbaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as rgbaT)[k] === \"number\",\n );\n if (isRgbaOb) return \"rgba\";\n\n const rgbKeys = [\"r\", \"g\", \"b\"] as (keyof rgbT)[];\n const isRgbOb = rgbKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as rgbT)[k] === \"number\",\n );\n if (isRgbOb) return \"rgb\";\n\n const hslaKeys = [\"h\", \"s\", \"l\", \"a\"] as (keyof hslaT)[];\n const isHslaOb = hslaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hslaT)[k] === \"number\",\n );\n if (isHslaOb) return \"hsla\";\n\n const hslKeys = [\"h\", \"s\", \"l\"] as (keyof hslT)[];\n const isHslOb = hslKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hslT)[k] === \"number\",\n );\n if (isHslOb) return \"hsl\";\n\n const hsvaKeys = [\"h\", \"s\", \"v\", \"a\"] as (keyof hsvaT)[];\n const isHsvaOb = hsvaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hsvaT)[k] === \"number\",\n );\n if (isHsvaOb) return \"hsva\";\n\n const hsvKeys = [\"h\", \"s\", \"v\"] as (keyof hsvT)[];\n const isHsvOb = hsvKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hsvT)[k] === \"number\",\n );\n if (isHsvOb) return \"hsv\";\n\n const hwbaKeys = [\"h\", \"w\", \"b\", \"a\"] as (keyof hwbaT)[];\n const isHwbaOb = hwbaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hwbaT)[k] === \"number\",\n );\n if (isHwbaOb) return \"hwba\";\n\n const hwbKeys = [\"h\", \"w\", \"b\"] as (keyof hwbT)[];\n const isHwbOb = hwbKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hwbT)[k] === \"number\",\n );\n if (isHwbOb) return \"hwb\";\n }\n\n return null;\n };\n\n // * MARK: RGB\n\n /** - Parse `RGB` or `RGBA` color string to an `object` */\n const RGB_string_to_object = (color: string): rgbaT => {\n color = color.trim().toLowerCase();\n const colorType = detectColorFormat(color);\n\n if (!colorType?.includes(\"rgb\")) {\n console.error(\n '[colorKit.getRgbObject] is unable to parse the string into an `RGB` object. As a result, the color \"black\" will be returned instead.',\n );\n return { r: 0, g: 0, b: 0, a: 1 };\n }\n\n let matches: RegExpMatchArray | null = null;\n const entry = COLORS_REGEX[colorType];\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(color)) {\n matches = color.match(regex);\n }\n }\n } else {\n matches = color.match(entry);\n }\n\n if (!matches || matches.length < 4) {\n console.error(\n '[colorKit.getRgbObject] An error occurred while attempting to destructuring `RGB` values from the given string. As a result, the color \"black\" will be returned instead.',\n );\n return { r: 0, g: 0, b: 0, a: 1 };\n }\n\n const r = parseInt(matches[1] || \"0\", 10),\n g = parseInt(matches[2] || \"0\", 10),\n b = parseInt(matches[3] || \"0\", 10),\n a = parseFloat(matches[4] ?? \"1\");\n\n return {\n r: clampRGB(r),\n g: clampRGB(g),\n b: clampRGB(b),\n a: clampAlpha(a),\n };\n };\n\n /** - Ensure that the `RGB` object values are within the correct range and that it has the alpha channel */\n const normalize_RGB_object = (color: rgbaT | rgbT): rgbaT => {\n return {\n r: clampRGB(color.r),\n g: clampRGB(color.g),\n b: clampRGB(color.b),\n a: clampAlpha((color as rgbaT).a ?? 1),\n };\n };\n\n /** - Convert an `RGB` or `RGBA` color to its corresponding `Hex` color */\n const RGB_to_HEX = (color: string | rgbaT | rgbT): string => {\n const { r, g, b, a } =\n typeof color === \"string\" ? RGB_string_to_object(color) : normalize_RGB_object(color);\n\n const red = numberToHexString(r),\n green = numberToHexString(g),\n blue = numberToHexString(b),\n alpha = a === 1 ? \"\" : numberToHexString(a * 255);\n\n return `#${red + green + blue + alpha}`;\n };\n\n /** - Convert `RGB` or `RGBA` color to an `RGBA` object representation */\n const RGB_to_RGB = (color: string | rgbaT | rgbT): rgbaT => {\n return typeof color === \"string\" ? RGB_string_to_object(color) : normalize_RGB_object(color);\n };\n\n /** - Convert an `RGB` or `RGBA` color to an `HSLA` object representation */\n const RGB_to_HSLA = (color: string | rgbaT | rgbT): hslaT => {\n const rgb =\n typeof color === \"string\" ? RGB_string_to_object(color) : normalize_RGB_object(color),\n r = rgb.r / 255,\n g = rgb.g / 255,\n b = rgb.b / 255,\n a = rgb.a;\n\n const max = Math.max(r, g, b),\n min = Math.min(r, g, b);\n\n let h = 0;\n let s = 0;\n let l = (max + min) / 2;\n\n if (max === min) {\n h = s = 0;\n } else {\n const d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n\n if (max === r) {\n h = (g - b) / d + (g < b ? 6 : 0);\n } else if (max === g) {\n h = (b - r) / d + 2;\n } else if (max === b) {\n h = (r - g) / d + 4;\n }\n\n h /= 6;\n }\n\n h = clampHue(h * 360);\n s = clamp100(s * 100);\n l = clamp100(l * 100);\n\n return { h, s, l, a: clampAlpha(a) };\n };\n\n /** - Convert `RGB` or `RGBA` color to an `HSVA` object representation */\n const RGB_to_HSVA = (color: string | rgbaT | rgbT): hsvaT => {\n const rgb =\n typeof color === \"string\" ? RGB_string_to_object(color) : normalize_RGB_object(color),\n r = rgb.r / 255,\n g = rgb.g / 255,\n b = rgb.b / 255,\n a = rgb.a;\n\n const max = Math.max(r, g, b),\n min = Math.min(r, g, b),\n d = max - min,\n v = max,\n s = max === 0 ? 0 : d / max;\n\n let h = 0;\n\n if (max === min) {\n h = 0;\n } else {\n if (max === r) {\n h = (g - b) / d + (g < b ? 6 : 0);\n } else if (max === g) {\n h = (b - r) / d + 2;\n } else if (max === b) {\n h = (r - g) / d + 4;\n }\n\n h = h / 6;\n }\n\n return {\n h: clampHue(h * 360),\n s: clamp100(s * 100),\n v: clamp100(v * 100),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `RGB` or `RGBA` color to an `HWBA` object representation */\n const RGB_to_HWBA = (color: string | rgbaT | rgbT): hwbaT => {\n const rgb =\n typeof color === \"string\" ? RGB_string_to_object(color) : normalize_RGB_object(color),\n red = rgb.r / 255,\n green = rgb.g / 255,\n blue = rgb.b / 255,\n a = rgb.a;\n\n const { h } = RGB_to_HSLA(color);\n\n const white = Math.min(red, green, blue) * 100;\n const black = (1 - Math.max(red, green, blue)) * 100;\n\n return {\n h: clampHue(h),\n w: clamp100(white),\n b: clamp100(black),\n a: clampAlpha(a),\n };\n };\n\n /** - Return the `RGB` color as a string, an array, or an object */\n const RGB_types = ({ r, g, b, a }: rgbaT): ColorTypes => {\n return {\n string: (forceAlpha?: boolean) => {\n r = Math.round(r);\n g = Math.round(g);\n b = Math.round(b);\n\n // auto\n if (typeof forceAlpha === \"undefined\") {\n if (typeof a === \"number\" && a !== 1) return `rgba(${r}, ${g}, ${b}, ${a})`;\n return `rgb(${r}, ${g}, ${b})`;\n }\n\n if (forceAlpha) return `rgba(${r}, ${g}, ${b}, ${a ?? 1})`;\n\n return `rgb(${r}, ${g}, ${b})`;\n },\n array: (roundValues = true) => {\n if (roundValues) {\n r = Math.round(r);\n g = Math.round(g);\n b = Math.round(b);\n }\n return [r, g, b, a];\n },\n object: (roundValues = true) => {\n if (roundValues) {\n r = Math.round(r);\n g = Math.round(g);\n b = Math.round(b);\n }\n return { r, g, b, a };\n },\n };\n };\n\n // * MARK: HSL\n\n /** - Parse `HSL` or `HSLA` color string to an `object` */\n const HSL_string_to_object = (color: string): hslaT => {\n color = color.trim().toLowerCase();\n const colorType = detectColorFormat(color);\n\n if (!colorType?.includes(\"hsl\")) {\n console.error(\n '[colorKit.getHslObject] is unable to parse the string into an `HSL` object. As a result, the color \"black\" will be returned instead.',\n );\n return { h: 0, s: 0, l: 0, a: 1 };\n }\n\n let matches: RegExpMatchArray | null = null;\n const entry = COLORS_REGEX[colorType as \"hsl\" | \"hsla\"];\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(color)) {\n matches = color.match(regex);\n }\n }\n } else {\n matches = color.match(entry);\n }\n\n if (!matches || matches.length < 3) {\n console.error(\n '[colorKit.getHslObject] An error occurred while attempting to destructuring `HSL` values from the given string. As a result, the color \"black\" will be returned instead.',\n );\n return { h: 0, s: 0, l: 0, a: 1 };\n }\n\n const h = parseInt(matches[1] || \"0\", 10),\n s = parseInt(matches[2] || \"0\", 10),\n l = parseInt(matches[3] || \"0\", 10),\n a = parseFloat(matches[4] ?? \"1\");\n\n return {\n h: clampHue(h),\n s: clamp100(s),\n l: clamp100(l),\n a: clampAlpha(a),\n };\n };\n\n /** - Ensure that the `HSL` object values are within the correct range and that it has the alpha channel */\n const normalize_HSL_object = (color: hslaT | hslT): hslaT => {\n return {\n h: clampHue(color.h),\n s: clamp100(color.s),\n l: clamp100(color.l),\n a: clampAlpha((color as hslaT).a ?? 1),\n };\n };\n\n /** - Convert `HSL` or `HSLA` color to an `RGBA` object representation */\n const HSL_to_RGBA = (color: string | hslaT | hslT): rgbaT => {\n const hsla =\n typeof color === \"string\" ? HSL_string_to_object(color) : normalize_HSL_object(color);\n\n const h = hsla.h / 360,\n s = hsla.s / 100,\n l = hsla.l / 100,\n a = hsla.a;\n\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s,\n p = 2 * l - q;\n\n const r = calculateHueValue(p, q, h + 1 / 3),\n g = calculateHueValue(p, q, h),\n b = calculateHueValue(p, q, h - 1 / 3);\n\n return {\n r: clampRGB(r * 255),\n g: clampRGB(g * 255),\n b: clampRGB(b * 255),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `HSL` or `HSLA` color to `HEX` color */\n const HSL_to_HEX = (color: string | hslaT | hslT): string => {\n const hsla =\n typeof color === \"string\" ? HSL_string_to_object(color) : normalize_HSL_object(color);\n const rgb = HSL_to_RGBA(hsla);\n\n const r = numberToHexString(rgb.r),\n g = numberToHexString(rgb.g),\n b = numberToHexString(rgb.b),\n a = rgb.a === 1 ? \"\" : numberToHexString(rgb.a * 255);\n\n return `#${r + g + b + a}`;\n };\n\n /** - Convert `HSL` or `HSLA` color to an `HSVA` object representation */\n const HSL_to_HSVA = (color: string | hslaT | hslT): hsvaT => {\n const hsla =\n typeof color === \"string\" ? HSL_string_to_object(color) : normalize_HSL_object(color);\n const h = hsla.h;\n\n const s = hsla.s / 100,\n l = hsla.l / 100,\n a = (hsla as hslaT).a ?? 1,\n v = l + s * Math.min(l, 1 - l),\n sNew = v === 0 ? 0 : 2 - (2 * l) / v;\n\n return {\n h: clampHue(h),\n s: clamp100(sNew * 100),\n v: clamp100(v * 100),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `HSL` or `HSLA` color to an `HWBA` object representation */\n const HSL_to_HWBA = (color: string | hslaT | hslT): hwbaT => {\n const hsva = HSL_to_HSVA(color);\n return HSV_to_HWBA(hsva);\n };\n\n /** - Convert `HSL` or `HSLA` color to an `HSLA` object representation */\n const HSL_to_HSL = (color: string | hslaT | hslT): hslaT => {\n return typeof color === \"string\" ? HSL_string_to_object(color) : normalize_HSL_object(color);\n };\n\n /** - Return the `HSL` color as a string, an array, or an object */\n const HSL_types = ({ h, s, l, a }: hslaT): ColorTypes => {\n return {\n string: (forceAlpha?: boolean) => {\n h = Math.round(h);\n s = Math.round(s);\n l = Math.round(l);\n\n // auto\n if (typeof forceAlpha === \"undefined\") {\n if (typeof a === \"number\" && a !== 1) return `hsla(${h}, ${s}%, ${l}%, ${a})`;\n return `hsl(${h}, ${s}%, ${l}%)`;\n }\n\n if (forceAlpha) return `hsla(${h}, ${s}%, ${l}%, ${a ?? 1})`;\n\n return `hsl(${h}, ${s}%, ${l}%)`;\n },\n array: (roundValues = true) => {\n if (roundValues) {\n h = Math.round(h);\n s = Math.round(s);\n l = Math.round(l);\n }\n return [h, s, l, a];\n },\n object: (roundValues = true) => {\n if (roundValues) {\n h = Math.round(h);\n s = Math.round(s);\n l = Math.round(l);\n }\n return { h, s, l, a };\n },\n };\n };\n\n // * MARK: HWB\n\n /** - Parse `HWB` or `HWBA` color strong to an `object` */\n const HWB_string_to_object = (color: string): hwbaT => {\n color = color.trim().toLowerCase();\n const colorType = detectColorFormat(color);\n\n if (!colorType?.includes(\"hwb\")) {\n console.error(\n '[colorKit.getHwbObject] is unable to parse the string into an `HWB` object. As a result, the color \"black\" will be returned instead.',\n );\n return { h: 0, w: 0, b: 0, a: 1 };\n }\n\n let matches: RegExpMatchArray | null = null;\n const entry = COLORS_REGEX[colorType as \"hwb\" | \"hwba\"];\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(color)) {\n matches = color.match(regex);\n }\n }\n } else {\n matches = color.match(entry);\n }\n\n if (!matches || matches.length < 4) {\n console.error(\n '[colorKit.getHwbObject] An error occurred while attempting to destructuring `HWB` values from the given string. As a result, the color \"black\" will be returned instead.',\n );\n return { h: 0, w: 0, b: 0, a: 1 };\n }\n\n const h = parseInt(matches[1] || \"0\", 10),\n w = parseInt(matches[2] || \"0\", 10),\n b = parseInt(matches[3] || \"0\", 10),\n a = parseFloat(matches[4] ?? \"1\");\n\n return {\n h: clampHue(h),\n w: clamp100(w),\n b: clamp100(b),\n a: clampAlpha(a),\n };\n };\n\n /** - Ensure that the `HWB` object values are within the correct range and that it has the alpha channel */\n const normalize_HWB_object = (color: hwbaT | hwbT): hwbaT => {\n return {\n h: clampHue(color.h),\n w: clamp100(color.w),\n b: clamp100(color.b),\n a: clampAlpha((color as hwbaT).a ?? 1),\n };\n };\n\n /** - Convert `HWB` or `HWBA` color to an `RGBA` object representation */\n const HWB_to_RGBA = (color: hwbaT | hwbT | string): rgbaT => {\n const hwba =\n typeof color === \"string\" ? HWB_string_to_object(color) : normalize_HWB_object(color);\n\n const h = hwba.h / 360,\n w = hwba.w / 100,\n b = hwba.b / 100,\n a = hwba.a;\n\n if (w + b >= 1) {\n const gray = clampRGB((w * 255) / (w + b));\n return {\n r: gray,\n g: gray,\n b: gray,\n a,\n };\n }\n\n const red = calculateHueValue(0, 1, h + 1 / 3) * (1 - w - b) + w,\n green = calculateHueValue(0, 1, h) * (1 - w - b) + w,\n blue = calculateHueValue(0, 1, h - 1 / 3) * (1 - w - b) + w;\n\n return {\n r: clampRGB(red * 255),\n g: clampRGB(green * 255),\n b: clampRGB(blue * 255),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `HWB` or `HWBA` color to an `Hex` color */\n const HWB_to_HEX = (color: hwbaT | hwbT | string): string => {\n const rgba = HWB_to_RGBA(color);\n return RGB_to_HEX(rgba);\n };\n\n /** - Convert `HWB` or `HWBA` color to an `HSVA` object representation */\n function HWB_to_HSVA(color: hwbaT | hwbT | string): hsvaT {\n const hwba =\n typeof color === \"string\" ? HWB_string_to_object(color) : normalize_HWB_object(color);\n\n const h = hwba.h % 360,\n w = hwba.w / 100,\n b = hwba.b / 100,\n a = hwba.a;\n\n const v = (1 - b) * 100;\n let s = (1 - w / (v / 100)) * 100;\n s = Number.isNaN(s) ? 0 : s;\n\n return {\n h: clampHue(h),\n s: clamp100(s),\n v: clamp100(v),\n a: clampAlpha(a),\n };\n }\n\n /** - Convert `HWB` or `HWBA` color to an `HSLA` object representation */\n const HWB_to_HSLA = (color: hwbaT | hwbT | string): hslaT => {\n const hsva = HWB_to_HSVA(color);\n return HSV_to_HSLA(hsva);\n };\n\n /** - Convert `HWB` or `HWBA` color to an `HWBA` object representation */\n const HWB_to_HWB = (color: hwbaT | hwbT | string): hwbaT => {\n return typeof color === \"string\" ? HWB_string_to_object(color) : normalize_HWB_object(color);\n };\n\n /** - Return the `HWB` color as a string, an array, or an object */\n const HWB_types = ({ h, w, b, a }: hwbaT): ColorTypes => {\n return {\n string: (forceAlpha?: boolean) => {\n h = Math.round(h);\n w = Math.round(w);\n b = Math.round(b);\n\n // auto\n if (typeof forceAlpha === \"undefined\") {\n if (typeof a === \"number\" && a !== 1) return `hwb(${h} ${w}% ${b}% / ${a})`;\n return `hwb(${h}, ${w}%, ${b}%)`;\n }\n\n if (forceAlpha) return `hwb(${h} ${w}% ${b}% / ${a ?? 1})`;\n\n return `hwb(${h} ${w}% ${b}%)`;\n },\n array: (roundValues = true) => {\n if (roundValues) {\n h = Math.round(h);\n w = Math.round(w);\n b = Math.round(b);\n }\n return [h, w, b, a];\n },\n object: (roundValues = true) => {\n if (roundValues) {\n h = Math.round(h);\n w = Math.round(w);\n b = Math.round(b);\n }\n return { h, w, b, a };\n },\n };\n };\n\n // * MARK: HSV\n\n /** - Parse `HSV` or `HSVA` color string to an `object` */\n const HSV_string_to_object = (color: string): hsvaT => {\n color = color.trim().toLowerCase();\n const colorType = detectColorFormat(color);\n\n if (!colorType?.includes(\"hsv\")) {\n console.error(\n '[colorKit.getHsvObject] is unable to parse the string into an `HSV` object. As a result, the color \"black\" will be returned instead.',\n );\n return { h: 0, s: 0, v: 0, a: 1 };\n }\n\n let matches: RegExpMatchArray | null = null;\n const entry = COLORS_REGEX[colorType as \"hsv\" | \"hsva\"];\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(color)) {\n matches = color.match(regex);\n }\n }\n } else {\n matches = color.match(entry);\n }\n\n if (!matches || matches.length < 4) {\n console.error(\n '[colorKit.getHsvObject] An error occurred while attempting to destructuring `HSV` values from the given string. As a result, the color \"black\" will be returned instead.',\n );\n return { h: 0, s: 0, v: 0, a: 1 };\n }\n\n const h = parseInt(matches[1] || \"0\", 10),\n s = parseInt(matches[2] || \"0\", 10),\n v = parseInt(matches[3] || \"0\", 10),\n a = parseFloat(matches[4] ?? \"1\");\n\n return {\n h: clampHue(h),\n s: clamp100(s),\n v: clamp100(v),\n a: clampAlpha(a),\n };\n };\n\n /** - Ensure that the `HSV` object values are within the correct range and that it has the alpha channel */\n const normalize_HSV_object = (color: hsvaT | hsvT): hsvaT => {\n return {\n h: clampHue(color.h),\n s: clamp100(color.s),\n v: clamp100(color.v),\n a: clampAlpha((color as hsvaT).a ?? 1),\n };\n };\n\n /** - Convert `HSV` color to an `RGBA` object representation */\n const HSV_to_RGBA = (color: hsvaT | hsvT | string): rgbaT => {\n const hsva =\n typeof color === \"string\" ? HSV_string_to_object(color) : normalize_HSV_object(color);\n\n const h = hsva.h / 360,\n s = hsva.s / 100,\n v = hsva.v / 100,\n a = hsva.a;\n\n const i = Math.floor(h * 6),\n f = h * 6 - i,\n p = v * (1 - s),\n q = v * (1 - f * s),\n t = v * (1 - (1 - f) * s);\n\n let r = 0,\n g = 0,\n b = 0;\n\n if (i % 6 === 0) {\n r = v;\n g = t;\n b = p;\n } else if (i % 6 === 1) {\n r = q;\n g = v;\n b = p;\n } else if (i % 6 === 2) {\n r = p;\n g = v;\n b = t;\n } else if (i % 6 === 3) {\n r = p;\n g = q;\n b = v;\n } else if (i % 6 === 4) {\n r = t;\n g = p;\n b = v;\n } else if (i % 6 === 5) {\n r = v;\n g = p;\n b = q;\n }\n\n return {\n r: clampRGB(r * 255),\n g: clampRGB(g * 255),\n b: clampRGB(b * 255),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `HSV` color to an `HSLA` object representation */\n const HSV_to_HSLA = (color: hsvaT | hsvT | string): hslaT => {\n const hsva =\n typeof color === \"string\" ? HSV_string_to_object(color) : normalize_HSV_object(color);\n\n const h = hsva.h,\n s = hsva.s / 100,\n v = hsva.v / 100,\n a = hsva.a;\n\n const l = ((2 - s) * v) / 2,\n sl = s * v,\n sln = l !== 0 && l !== 1 ? sl / (l < 0.5 ? l * 2 : 2 - l * 2) : sl;\n\n return {\n h: clampHue(h),\n s: clamp100(sln * 100),\n l: clamp100(l * 100),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `HSV` color to an `Hex` color */\n const HSV_to_HEX = (color: hsvaT | hsvT | string): string => {\n const rgba = HSV_to_RGBA(color);\n const hex = RGB_to_HEX(rgba);\n return hex;\n };\n\n /** - Convert `HSV` color to an `HWBA` object representation */\n const HSV_to_HWBA = (color: hsvaT | hsvT | string): hwbaT => {\n const { h, s, v, a } =\n typeof color === \"string\" ? HSV_string_to_object(color) : normalize_HSV_object(color);\n\n const w = (1 - s / 100) * v,\n b = (1 - v / 100) * 100;\n\n return {\n h: clampHue(h),\n w: clamp100(w),\n b: clamp100(b),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `HSV` color to an `HSVA` object representation */\n const HSV_to_HSV = (color: hsvaT | hsvT | string): hsvaT => {\n return typeof color === \"string\" ? HSV_string_to_object(color) : normalize_HSV_object(color);\n };\n\n /** - Return the `HSV` color as a string, an array, or an object */\n const HSV_types = ({ h, s, v, a }: hsvaT): ColorTypes => {\n return {\n string: (forceAlpha?: boolean) => {\n h = Math.round(h);\n s = Math.round(s);\n v = Math.round(v);\n\n // auto\n if (typeof forceAlpha === \"undefined\") {\n if (typeof a === \"number\" && a !== 1) return `hsva(${h}, ${s}%, ${v}%, ${a})`;\n return `hsv(${h}, ${s}%, ${v}%)`;\n }\n\n if (forceAlpha) return `hsva(${h}, ${s}%, ${v}%, ${a ?? 1})`;\n\n return `hsv(${h}, ${s}%, ${v}%)`;\n },\n array: (roundValues = true) => {\n if (roundValues) {\n h = Math.round(h);\n s = Math.round(s);\n v = Math.round(v);\n }\n return [h, s, v, a];\n },\n object: (roundValues = true) => {\n if (roundValues) {\n h = Math.round(h);\n s = Math.round(s);\n v = Math.round(v);\n }\n return { h, s, v, a };\n },\n };\n };\n\n // * MARK: HEX\n\n /** - Convert any `HEX` color to 8-digit `HEX` color (#rrggbbaa) */\n const normalize_HEX = (color: string | number): string => {\n if (typeof color === \"number\") {\n return `#${color.toString(16).padStart(8, \"0\")}`;\n }\n\n color = color.trim().toLowerCase();\n const colorType = detectColorFormat(color);\n\n if (!colorType?.includes(\"hex\")) {\n console.error(\n '[colorKit.normalizeHexColor] is unable to normalize the `HEX` string provided. As a result, the color \"black\" will be returned instead.',\n );\n return \"#000000ff\";\n }\n\n const hex = color.replace(/^#/, \"\").split(\"\");\n\n if (hex.length === 3) return `#${hex.map((x) => x + x).join(\"\")}ff`;\n if (hex.length === 4) return `#${hex.map((x) => x + x).join(\"\")}`;\n if (hex.length === 6) return `#${hex.join(\"\")}ff`;\n\n return color;\n };\n\n /** - Convert any `HEX` color to an `RGBA` object representation */\n const HEX_to_RGBA = (color: string | number): rgbaT => {\n const hex = normalize_HEX(color);\n\n let matches: RegExpMatchArray | null = null;\n const entry = COLORS_REGEX.hex8;\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(hex)) matches = hex.match(regex);\n }\n } else {\n matches = hex.match(entry);\n }\n\n if (!matches || matches.length < 4) {\n console.error(\n '[colorKit.HEX_RGBA] An error occurred while attempting to destructuring `HEX` values from the given string. As a result, the color \"black\" will be returned instead.',\n );\n return { r: 0, g: 0, b: 0, a: 1 };\n }\n\n const r = parseInt(matches[1] || \"0\", 16),\n g = parseInt(matches[2] || \"0\", 16),\n b = parseInt(matches[3] || \"0\", 16),\n a = parseInt(matches[4] || \"ff\", 16) / 255;\n\n return {\n r: clampRGB(r),\n g: clampRGB(g),\n b: clampRGB(b),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert any `HEX` color to an `HSVA` object representation */\n const HEX_to_HSVA = (color: string | number): hsvaT => {\n const rgb = HEX_to_RGBA(color);\n const hsva = RGB_to_HSVA(rgb);\n return hsva;\n };\n\n /** - Convert any `HEX` color to an `HSLA` object representation */\n const HEX_to_HSLA = (color: string): hslaT => {\n const rgb = HEX_to_RGBA(color);\n return RGB_to_HSLA(rgb);\n };\n\n /** - Convert any `HEX` color to an `HWBA` object representation */\n const HEX_to_HWBA = (color: string): hwbaT => {\n const rgba = HEX_to_RGBA(color);\n return RGB_to_HWBA(rgba);\n };\n\n // * MARK: Color conversions\n\n /** - Convert `HSL`, `HSV`, `HWB`, or `RGB` color to the `HEX` color format. */\n const HEX = (color: SupportedColorFormats): string => {\n // named color\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n\n if (Object.hasOwn(NAMED_COLORS, color)) {\n color = NAMED_COLORS[color as keyof typeof NAMED_COLORS] as string;\n }\n }\n\n const colorType = detectColorFormat(color);\n\n // RGB to HEX\n if (colorType === \"rgb\" || colorType === \"rgba\") {\n return RGB_to_HEX(color as string | rgbT | rgbaT);\n }\n\n // HSL to HEX\n if (colorType === \"hsl\" || colorType === \"hsla\") {\n return HSL_to_HEX(color as string | hslaT | hslT);\n }\n\n // HSV to HEX\n if (colorType === \"hsv\" || colorType === \"hsva\") {\n return HSV_to_HEX(color as string | hsvaT | hsvT);\n }\n\n // HWB to HEX\n if (colorType === \"hwb\" || colorType === \"hwba\") {\n return HWB_to_HEX(color as string | hwbaT | hwbT);\n }\n\n // HEX\n if (colorType?.includes(\"hex\")) {\n return normalize_HEX(color as string | number);\n }\n\n // ! error\n console.error(\n '[colorKit.HEX] An error occurred while attempting to convert the provided parameter into an `HEX` color. As a result, the default color \"black\" will be used instead.',\n );\n\n return \"#000000\";\n };\n\n /** - Convert `HSL`, `HSV`, `HWB`, or `HEX` color to the `RGB` color format. */\n const RGB = (color: SupportedColorFormats): ColorTypes => {\n // named color\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n\n if (Object.hasOwn(NAMED_COLORS, color)) {\n color = NAMED_COLORS[color as keyof typeof NAMED_COLORS] as string;\n }\n }\n\n const colorType = detectColorFormat(color);\n\n // HEX to RGB\n if (colorType?.includes(\"hex\")) {\n const rgb = HEX_to_RGBA(color as string | number);\n return RGB_types(rgb);\n }\n\n // HSL to RGB\n if (colorType === \"hsl\" || colorType === \"hsla\") {\n const rgb = HSL_to_RGBA(color as string | hslaT | hslT);\n return RGB_types(rgb);\n }\n\n // HSV to RGB\n if (colorType === \"hsv\" || colorType === \"hsva\") {\n const rgb = HSV_to_RGBA(color as string | hsvaT | hsvT);\n return RGB_types(rgb);\n }\n\n // HWB to RGB\n if (colorType === \"hwb\" || colorType === \"hwba\") {\n const rgb = HWB_to_RGBA(color as string | hwbaT | hwbT);\n return RGB_types(rgb);\n }\n\n // RGB to normalized RGB\n if (colorType === \"rgb\" || colorType === \"rgba\") {\n const rgba = RGB_to_RGB(color as string | rgbaT | rgbT);\n return RGB_types(rgba);\n }\n\n // ! error\n console.error(\n '[colorKit.RGB] An error occurred while attempting to convert the provided parameter into an `RGB` color. As a result, the default color \"black\" will be used instead.',\n );\n\n return RGB_types({ r: 0, g: 0, b: 0, a: 1 });\n };\n\n /** - Convert `HEX`, `HSV`, `HWB`, or `RGB` color to the `HSL` color format. */\n const HSL = (color: SupportedColorFormats): ColorTypes => {\n // named color\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n\n if (Object.hasOwn(NAMED_COLORS, color)) {\n color = NAMED_COLORS[color as keyof typeof NAMED_COLORS] as string;\n }\n }\n\n const colorType = detectColorFormat(color);\n\n // HEX to HSL\n if (colorType?.includes(\"hex\")) {\n const hsla = HEX_to_HSLA(color as string);\n return HSL_types(hsla);\n }\n\n // RGB to HSL\n if (colorType === \"rgb\" || colorType === \"rgba\") {\n const hsla = RGB_to_HSLA(color as string | rgbaT | rgbT);\n return HSL_types(hsla);\n }\n\n // HSV to HSL\n if (colorType === \"hsv\" || colorType === \"hsva\") {\n const hsla = HSV_to_HSLA(color as string | hsvaT | hsvT);\n return HSL_types(hsla);\n }\n\n // HWB to HSL\n if (colorType === \"hwb\" || colorType === \"hwba\") {\n const hsla = HWB_to_HSLA(color as string | hwbaT | hwbT);\n return HSL_types(hsla);\n }\n\n // HSL to normalized HSL\n if (colorType === \"hsl\" || colorType === \"hsla\") {\n const hsla = HSL_to_HSL(color as string | hslaT | hslT);\n return HSL_types(hsla);\n }\n\n // ! error\n console.error(\n '[colorKit.HSL] An error occurred while attempting to convert the provided parameter into an `HSL` color. As a result, the default color \"black\" will be used instead.',\n );\n\n return HSL_types({ h: 0, s: 0, l: 0, a: 1 });\n };\n\n /** - Convert `HSL`, `HEX`, `HSV`, or `RGB` color to the `HWB` color format. */\n const HWB = (color: SupportedColorFormats): ColorTypes => {\n // named color\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n\n if (Object.hasOwn(NAMED_COLORS, color)) {\n color = NAMED_COLORS[color as keyof typeof NAMED_COLORS] as string;\n }\n }\n\n const colorType = detectColorFormat(color);\n\n // HEX to HWB\n if (colorType?.includes(\"hex\")) {\n const hwba = HEX_to_HWBA(color as string);\n return HWB_types(hwba);\n }\n\n // RGB to HWB\n if (colorType === \"rgb\" || colorType === \"rgba\") {\n const hwba = RGB_to_HWBA(color as string | rgbaT | rgbT);\n return HWB_types(hwba);\n }\n\n // HSL to HWB\n if (colorType === \"hsl\" || colorType === \"hsla\") {\n const hwba = HSL_to_HWBA(color as string | hslaT | hslT);\n return HWB_types(hwba);\n }\n\n // HSV to HWB\n if (colorType === \"hsv\" || colorType === \"hsva\") {\n const hwba = HSV_to_HWBA(color as string | hsvaT | hsvT);\n return HWB_types(hwba);\n }\n\n // HWB to normalized HWB\n if (colorType === \"hwb\" || colorType === \"hwba\") {\n const hwba = HWB_to_HWB(color as string | hwbaT | hwbT);\n return HWB_types(hwba);\n }\n\n // ! error\n console.error(\n '[colorKit.HWB] An error occurred while attempting to convert the provided parameter into an `HWB` color. As a result, the default color \"black\" will be used instead.',\n );\n\n return HWB_types({ h: 0, w: 0, b: 100, a: 1 });\n };\n\n /** - Convert `HSL`, `HEX`, `HWB`, or `RGB` color to the `HSV` color format. */\n const HSV = (color: SupportedColorFormats): ColorTypes => {\n // named color\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n\n if (Object.hasOwn(NAMED_COLORS, color)) {\n color = NAMED_COLORS[color as keyof typeof NAMED_COLORS] as string;\n }\n }\n\n const colorType = detectColorFormat(color);\n\n // HEX to HSV\n if (colorType?.includes(\"hex\")) {\n const hsva = HEX_to_HSVA(color as string);\n return HSV_types(hsva);\n }\n\n // RGB to HSV\n if (colorType === \"rgb\" || colorType === \"rgba\") {\n const hsva = RGB_to_HSVA(color as string | rgbaT | rgbT);\n return HSV_types(hsva);\n }\n\n // HSL to HSV\n if (colorType === \"hsl\" || colorType === \"hsla\") {\n const hsva = HSL_to_HSVA(color as string | hslaT | hslT);\n return HSV_types(hsva);\n }\n\n // HWB to HSV\n if (colorType === \"hwb\" || colorType === \"hwba\") {\n const hsva = HWB_to_HSVA(color as string | hwbaT | hwbT);\n return HSV_types(hsva);\n }\n\n // HSV to normalized HSV\n if (colorType === \"hsv\" || colorType === \"hsva\") {\n const hsva = HSV_to_HSV(color as string | hsvaT | hsvT);\n return HSV_types(hsva);\n }\n\n // ! error\n console.error(\n '[colorKit.HSV] An error occurred while attempting to convert the provided parameter into an `HSV` color. As a result, the default color \"black\" will be used instead.',\n );\n\n return HSV_types({ h: 0, s: 0, v: 0, a: 1 });\n };\n\n // * MARK: Color Information\n\n /** - Identify the color format of a given `string` or `object`, and return `null` for invalid colors. */\n const getFormat = (color: SupportedColorFormats): ColorFormats | \"named\" | null => {\n // color int\n if (typeof color === \"number\") {\n // eslint-disable-next-line no-bitwise\n if (color >>> 0 === color && color >= 0 && color <= 0xffffffff) return \"hex8\";\n return null;\n }\n\n // color string\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n if (Object.hasOwn(NAMED_COLORS, color)) return \"named\";\n\n for (const key in COLORS_REGEX) {\n const format = key as ColorFormats;\n const entry = COLORS_REGEX[format];\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(color)) return format;\n }\n continue;\n }\n if (entry.test(color)) return format;\n }\n }\n\n // color object\n if (typeof color === \"object\") {\n const rgbaKeys = [\"r\", \"g\", \"b\", \"a\"] as (keyof rgbaT)[];\n const isRgbaOb = rgbaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as rgbaT)[k] === \"number\",\n );\n if (isRgbaOb) return \"rgba\";\n\n const rgbKeys = [\"r\", \"g\", \"b\"] as (keyof rgbT)[];\n const isRgbOb = rgbKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as rgbT)[k] === \"number\",\n );\n if (isRgbOb) return \"rgb\";\n\n const hslaKeys = [\"h\", \"s\", \"l\", \"a\"] as (keyof hslaT)[];\n const isHslaOb = hslaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hslaT)[k] === \"number\",\n );\n if (isHslaOb) return \"hsla\";\n\n const hslKeys = [\"h\", \"s\", \"l\"] as (keyof hslT)[];\n const isHslOb = hslKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hslT)[k] === \"number\",\n );\n if (isHslOb) return \"hsl\";\n\n const hsvaKeys = [\"h\", \"s\", \"v\", \"a\"] as (keyof hsvaT)[];\n const isHsvaOb = hsvaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hsvaT)[k] === \"number\",\n );\n if (isHsvaOb) return \"hsva\";\n\n const hsvKeys = [\"h\", \"s\", \"v\"] as (keyof hsvT)[];\n const isHsvOb = hsvKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hsvT)[k] === \"number\",\n );\n if (isHsvOb) return \"hsv\";\n\n const hwbaKeys = [\"h\", \"w\", \"b\", \"a\"] as (keyof hwbaT)[];\n const isHwbaOb = hwbaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hwbaT)[k] === \"number\",\n );\n if (isHwbaOb) return \"hwba\";\n\n const hwbKeys = [\"h\", \"w\", \"b\"] as (keyof hwbT)[];\n const isHwbOb = hwbKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hwbT)[k] === \"number\",\n );\n if (isHwbOb) return \"hwb\";\n }\n\n return null;\n };\n\n /** - Get the `red` channel value of a given color. */\n const getRed = (color: SupportedColorFormats): number => {\n const { r } = RGB(color).object();\n return r;\n };\n\n /** - Get the `green` channel value of a given color. */\n const getGreen = (color: SupportedColorFormats): number => {\n const { g } = RGB(color).object();\n return g;\n };\n\n /** - Get the `blue` channel value of a given color. */\n const getBlue = (color: SupportedColorFormats): number => {\n const { b } = RGB(color).object();\n return b;\n };\n\n /** - Get the `hue` channel value of a given color. */\n const getHue = (color: SupportedColorFormats): number => {\n const { h } = HSL(color).object();\n return h;\n };\n\n /** - Get the `saturation` value of a given color. */\n const getSaturation = (color: SupportedColorFormats): number => {\n const { s } = HSL(color).object();\n return s;\n };\n\n /**\n * - Get color's HSL `luminosity` channel value.\n * - If you want the overall `luminosity` of a color use `getLuminanceWCAG` method.\n */\n const getLuminance = (color: SupportedColorFormats): number => {\n const { l } = HSL(color).object();\n return l;\n };\n\n /** - Get the HSV's `value` (brightness) channel value of a given color. */\n const getBrightness = (color: SupportedColorFormats): number => {\n const { v } = HSV(color).object();\n return v;\n };\n\n /** - Returns the perceived `luminance` of a color, from `0-1` as defined by Web Content Accessibility Guidelines (Version 2.0). */\n const getLuminanceWCAG = (color: SupportedColorFormats): number => {\n const { r, g, b } = RGB(color).object(false);\n const a = [r, g, b].map((v) =>\n v / 255 <= 0.03928 ? v / 255 / 12.92 : ((v / 255 + 0.055) / 1.055) ** 2.4,\n );\n return (a[0] || 0) * 0.2126 + (a[1] || 0) * 0.7152 + (a[2] || 0) * 0.0722;\n };\n\n /** - Returns a boolean indicating whether the color is considered \"dark\" or not */\n const isDark = (color: SupportedColorFormats): boolean => {\n const luminance = getLuminanceWCAG(color);\n return luminance < 0.5;\n };\n\n /** - Returns a boolean indicating whether the color is considered \"light\" or not */\n const isLight = (color: SupportedColorFormats): boolean => {\n const luminance = getLuminanceWCAG(color);\n return luminance >= 0.5;\n };\n\n /**\n * - Check if two colors are similar within a specified tolerance.\n *\n * @example\n * const tolerance = 0;\n * const isEqual = colorKit.areColorsEqual('#f00', 'red', tolerance); // true\n */\n const areColorsEqual = (\n color1: SupportedColorFormats,\n color2: SupportedColorFormats,\n tolerance = 0,\n ): boolean => {\n const rgb1 = RGB(color1).object();\n const rgb2 = RGB(color2).object();\n\n const deltaR = rgb1.r - rgb2.r;\n const deltaG = rgb1.g - rgb2.g;\n const deltaB = rgb1.b - rgb2.b;\n const difference = Math.sqrt(deltaR * deltaR + deltaG * deltaG + deltaB * deltaB);\n\n return difference <= tolerance;\n };\n\n /** - Calculates the contrast ratio between two colors, useful for ensuring accessibility and readability. */\n const contrastRatio = (color1: SupportedColorFormats, color2: SupportedColorFormats): number => {\n const luminance1 = getLuminanceWCAG(color1);\n const luminance2 = getLuminanceWCAG(color2);\n const contrast =\n (Math.max(luminance1, luminance2) + 0.05) / (Math.min(luminance1, luminance2) + 0.05);\n return Math.round(contrast * 100) / 100;\n };\n\n // * MARK: Color Manipulation\n\n const returnColorObject = (color: SupportedColorFormats) => {\n return {\n hex() {\n return HEX(color);\n },\n rgb() {\n return RGB(color);\n },\n hsl() {\n return HSL(color);\n },\n hsv() {\n return HSV(color);\n },\n hwb() {\n return HWB(color);\n },\n };\n };\n\n // * MARK: Red Manuipulation\n /** Set the `red` value of a color to a specific amount. */\n const setRed = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { g, b, a } = RGB(color).object();\n const newR = clampRGB(amount);\n const newColor = { r: newR, g, b, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Increase the `red` value of a color by the given percentage/amount.\n *\n * @example\n * increaseRed('rgb(100, 100, 100)', 20).hex();\n * increaseRed('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const increaseRed = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const red = typeof amount === \"string\" ? r + r * (parseFloat(amount) / 100) : r + amount;\n const newR = clampRGB(red);\n const newColor = { r: newR, g, b, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Decrease the `red` value of a color by the given percentage/amount\n *\n * @example\n * decreaseRed('rgb(100, 100, 100)', 20).hex();\n * decreaseRed('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const decreaseRed = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const red = typeof amount === \"string\" ? r - r * (parseFloat(amount) / 100) : r - amount;\n const newR = clampRGB(red);\n const newColor = { r: newR, g, b, a };\n\n return returnColorObject(newColor);\n };\n\n // * MARK: Green Manuipulation\n /** - Set the `green` value of a color to a specific amount. */\n const setGreen = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { r, b, a } = RGB(color).object();\n const newG = clampRGB(amount);\n const newColor = { r, g: newG, b, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Increase the `green` value of a color by the given percentage.\n *\n * @example\n * increaseGreen('rgb(100, 100, 100)', 20).hex();\n * increaseGreen('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const increaseGreen = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const green = typeof amount === \"string\" ? g + g * (parseFloat(amount) / 100) : g + amount;\n const newG = clampRGB(green);\n const newColor = { r, g: newG, b, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Decrease the `green` value of a color by the given percentage.\n *\n * @example\n * decreaseGreen('rgb(100, 100, 100)', 20).hex();\n * decreaseGreen('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const decreaseGreen = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const green = typeof amount === \"string\" ? g - g * (parseFloat(amount) / 100) : g - amount;\n const newG = clampRGB(green);\n const newColor = { r, g: newG, b, a };\n\n return returnColorObject(newColor);\n };\n\n // * MARK: Blue Manuipulation\n /** - Set the `blue` value of a color to a specific amount. */\n const setBlue = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { r, g, a } = RGB(color).object();\n const newB = clampRGB(amount);\n const newColor = { r, g, b: newB, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Increase the `blue` value of a color by the given percentage.\n *\n * @example\n * increaseBlue('rgb(100, 100, 100)', 20).hex();\n * increaseBlue('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const increaseBlue = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const blue = typeof amount === \"string\" ? b + b * (parseFloat(amount) / 100) : b + amount;\n const newB = clampRGB(blue);\n const newColor = { r, g, b: newB, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Decrease the `blue` value of a color by the given percentage.\n *\n * @example\n * decreaseBlue('rgb(100, 100, 100)', 20).hex();\n * decreaseBlue('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const decreaseBlue = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const blue = typeof amount === \"string\" ? b - b * (parseFloat(amount) / 100) : b - amount;\n const newB = clampRGB(blue);\n const newColor = { r, g, b: newB, a };\n\n return returnColorObject(newColor);\n };\n\n //* MARK: Alpha Manuipulation\n /** - Get the `alpha` value of a given color. */\n const getAlpha = (color: SupportedColorFormats): number => {\n const { a } = RGB(color).object();\n return a;\n };\n\n /** - Set the `alpha` value of a color to a specific amount. */\n const setAlpha = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { r, g, b } = RGB(color).object();\n const newA = clampAlpha(amount);\n const newColor = { r, g, b, a: newA };\n\n return returnColorObject(newColor);\n };\n\n /** Increase the `alpha` value of a color by the given percentage. */\n const increaseAlpha = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const alpha = typeof amount === \"string\" ? a + a * (parseFloat(amount) / 100) : a + amount;\n const newA = clampAlpha(alpha);\n const newColor = { r, g, b, a: newA };\n\n return returnColorObject(newColor);\n };\n\n /** Decrease the `alpha` value of a color by the given percentage. */\n const decreaseAlpha = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const alpha = typeof amount === \"string\" ? a - a * (parseFloat(amount) / 100) : a - amount;\n const newA = clampAlpha(alpha);\n const newColor = { r, g, b, a: newA };\n\n return returnColorObject(newColor);\n };\n\n // * MARK: Hue Manuipulation\n /** - Set the `hue` value of a color to a specific amount. */\n const setHue = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { s, l, a } = HSL(color).object();\n const newH = clampHue(amount);\n const newColor = { h: newH, s, l, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Increase the `hue` value of a color by the given percentage/amount.\n *\n * @example\n * increaseHue('rgb(100, 100, 100)', 20).hex();\n * increaseHue('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const increaseHue = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const hue = typeof amount === \"string\" ? h + h * (parseFloat(amount) / 100) : h + amount;\n const newH = clampHue(hue);\n const newColor = { h: newH, s, l, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Decrease the `hue` value of a color by the given percentage/amount.\n *\n * @example\n * decreaseHue('rgb(100, 100, 100)', 20).hex();\n * decreaseHue('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const decreaseHue = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const hue = typeof amount === \"string\" ? h - h * (parseFloat(amount) / 100) : h - amount;\n const newH = clampHue(hue);\n const newColor = { h: newH, s, l, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * - Spin the `hue` channel by a certain percentage/amount.\n *\n * @example\n * spin('red', 20).hex();\n * spin('rgb(255, 0, 0)', '20%').rgb().string();\n */\n const spin = (color: SupportedColorFormats, degree: number | string): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const spinDegree = typeof degree === \"string\" ? s * (parseFloat(degree) / 100) : degree;\n const newColor = { h: Math.round((h + spinDegree) % 360), s, l, a };\n\n return returnColorObject(newColor);\n };\n\n // * MARK: Saturation Manuipulation\n /** - Set the `saturation` value of a color to a specific amount. */\n const setSaturation = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { h, l, a } = HSL(color).object();\n const newS = clamp100(amount);\n const saturatedColor = { h, s: newS, l, a };\n\n return returnColorObject(saturatedColor);\n };\n\n /**\n * - Increase the saturation of the given color by a certain percentage/amount.\n *\n * @example\n * saturate('red', 20).hex();\n * saturate('rgb(255, 0, 0)', '20%').rgb().string();\n */\n const saturate = (color: SupportedColorFormats, amount: number | string): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const saturation = typeof amount === \"string\" ? s + s * (parseFloat(amount) / 100) : s + amount;\n const newS = clamp100(saturation);\n const saturatedColor = { h, s: newS, l, a };\n\n return returnColorObject(saturatedColor);\n };\n\n /**\n * - Decrease the saturation of the given color by a certain percentage/amount.\n *\n * @example\n * saturate('red', 20).hex();\n * saturate('rgb(255, 0, 0)', '20%').rgb().string();\n */\n const desaturate = (color: SupportedColorFormats, amount: number | string): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const saturation = typeof amount === \"string\" ? s - s * (parseFloat(amount) / 100) : s - amount;\n const newS = clamp100(saturation);\n const desaturatedColor = { h, s: newS, l, a };\n\n return returnColorObject(desaturatedColor);\n };\n\n // * MARK: Brightness Manuipulation\n /** - Set HSL's `luminosity` channel for a given color to a specific amount. */\n const setLuminance = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { h, s, a } = HSL(color).object();\n const newL = clamp100(amount);\n const newColor = { h, s, l: newL, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * - Increase the brightness of the given color by a certain percentage/amount.\n *\n * @example\n * brighten('red', 20).hex();\n * brighten('rgb(255, 0, 0)', '20%').rgb().string();\n */\n const brighten = (color: SupportedColorFormats, amount: number | string): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const lum = typeof amount === \"string\" ? l + l * (parseFloat(amount) / 100) : l + amount;\n const newL = clamp100(lum);\n const brightenedColor = { h, s, l: newL, a };\n\n return returnColorObject(brightenedColor);\n };\n\n /**\n * - Decrease the brightness of the given color by a certain percentage/amount.\n *\n * @example\n * darken('red', 20).hex();\n * darken('rgb(255, 0, 0)', '20%').rgb().string();\n */\n const darken = (color: SupportedColorFormats, amount: number | string): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const lum = typeof amount === \"string\" ? l - l * (parseFloat(amount) / 100) : l - amount;\n const newL = clamp100(lum);\n const darkenedColor = { h, s, l: newL, a };\n\n return returnColorObject(darkenedColor);\n };\n\n /** - Set HSV's `value` (brightness) channel for a given color to a specific amount. */\n const setBrightness = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { h, s, a } = HSV(color).object();\n const newV = clamp100(amount);\n const newColor = { h, s, v: newV, a };\n\n return returnColorObject(newColor);\n };\n\n /** Increase HSV's `value` (brightness) channel value of a color by the given percentage/amount. */\n const increaseBrightness = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { h, s, v, a } = HSV(color).object();\n const value = typeof amount === \"string\" ? v + v * (parseFloat(amount) / 100) : v + amount;\n const newV = clamp100(value);\n const newColor = { h, s, v: newV, a };\n\n return returnColorObject(newColor);\n };\n\n /** Decrease HSV's `value` (brightness) channel value of a color by the given percentage/amount. */\n const decreaseBrightness = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { h, s, v, a } = HSV(color).object();\n const value = typeof amount === \"string\" ? v - v * (parseFloat(amount) / 100) : v - amount;\n const newV = clamp100(value);\n const newColor = { h, s, v: newV, a };\n\n return returnColorObject(newColor);\n };\n\n // * MARK: Color Utilities\n\n /**\n * - Blends two colors by a certain amount.\n *\n * @example\n * blend('yellow', 'red', 50).hex(); // #ff8000\n */\n const blend = (\n color1: SupportedColorFormats,\n color2: SupportedColorFormats,\n percentage: number,\n ): ConversionMethods => {\n percentage = percentage / 100;\n\n const rgba1 = RGB(color1).object();\n const rgba2 = RGB(color2).object();\n\n const r = clampRGB(rgba1.r * (1 - percentage) + rgba2.r * percentage),\n g = clampRGB(rgba1.g * (1 - percentage) + rgba2.g * percentage),\n b = clampRGB(rgba1.b * (1 - percentage) + rgba2.b * percentage),\n a = clampAlpha(rgba1.a * (1 - percentage) + rgba2.a * percentage);\n\n const blendedColor = { r, g, b, a };\n\n return returnColorObject(blendedColor);\n };\n\n /** - Invert (negate) a color, black becomes white, white becomes black, blue becomes orange and so on. */\n const invert = (color: SupportedColorFormats): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const invertedColor = { r: 255 - r, g: 255 - g, b: 255 - b, a };\n return returnColorObject(invertedColor);\n };\n\n /** - Completely desaturate a color into grayscale. */\n const grayscale = (color: SupportedColorFormats): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const gray = clampRGB(r * 0.3 + g * 0.59 + b * 0.11);\n const grayColor = { r: gray, g: gray, b: gray, a };\n\n return returnColorObject(grayColor);\n };\n\n /** - Generate a random color from `HSL` values. */\n const randomHslColor = ({\n h = [0, 360],\n s = [0, 100],\n l = [0, 100],\n a = [1, 1],\n } = {}): ConversionMethods => {\n const random = {\n h: clampHue(randomNumber(h[0] ?? 0, h[1] ?? 360)),\n s: clamp100(randomNumber(s[0] ?? 0, s[1] ?? 100)),\n l: clamp100(randomNumber(l[0] ?? 0, l[1] ?? 100)),\n a: clampAlpha(randomNumber(a[0] ?? 1, a[1] ?? 1)),\n };\n\n return returnColorObject(random);\n };\n\n /** - Generate a random color from `HSV` values. */\n const randomHsvColor = ({\n h = [0, 360],\n s = [0, 100],\n v = [0, 100],\n a = [1, 1],\n } = {}): ConversionMethods => {\n const random = {\n h: clampHue(randomNumber(h[0] ?? 0, h[1] ?? 360)),\n s: clamp100(randomNumber(s[0] ?? 0, s[1] ?? 100)),\n v: clamp100(randomNumber(v[0] ?? 0, v[1] ?? 100)),\n a: clampAlpha(randomNumber(a[0] ?? 1, a[1] ?? 1)),\n };\n\n return returnColorObject(random);\n };\n\n /** - Generate a random color from `RGB` values. */\n const randomRgbColor = ({\n r = [0, 255],\n g = [0, 255],\n b = [0, 255],\n a = [1, 1],\n } = {}): ConversionMethods => {\n const random = {\n r: clampRGB(randomNumber(r[0] ?? 0, r[1] ?? 255)),\n g: clampRGB(randomNumber(g[0] ?? 0, g[1] ?? 255)),\n b: clampRGB(randomNumber(b[0] ?? 0, b[1] ?? 255)),\n a: clampAlpha(randomNumber(a[0] ?? 1, a[1] ?? 1)),\n };\n\n return returnColorObject(random);\n };\n\n /** - Generate a random color from `HWB` values. */\n const randomHwbColor = ({\n h = [0, 360],\n w = [0, 100],\n b = [0, 100],\n a = [1, 1],\n } = {}): ConversionMethods => {\n const random = {\n h: clampHue(randomNumber(h[0] ?? 0, h[1] ?? 360)),\n w: clamp100(randomNumber(w[0] ?? 0, w[1] ?? 100)),\n b: clamp100(randomNumber(b[0] ?? 0, b[1] ?? 100)),\n a: clampAlpha(randomNumber(a[0] ?? 1, a[1] ?? 1)),\n };\n\n return returnColorObject(random);\n };\n\n /** - Returns the first color with the desired contrast ratio against the second color */\n const adjustContrast = (\n color1: SupportedColorFormats,\n color2: SupportedColorFormats,\n ratio = 4.5,\n ): ConversionMethods => {\n const contrast = contrastRatio(color1, color2);\n const color1RGB = RGB(color1).object();\n const channels = [\"r\", \"g\", \"b\"] as const;\n\n function adjustLuminance(colorRGB: rgbaT, by: number) {\n const r = clampRGB(colorRGB.r + by);\n const g = clampRGB(colorRGB.g + by);\n const b = clampRGB(colorRGB.b + by);\n return { r, g, b, a: colorRGB.a };\n }\n\n let newColor = color1RGB;\n\n //* increase contrast\n if (ratio && contrast < ratio) {\n while (contrastRatio(newColor, color2) < ratio) {\n const adjustBy = isDark(color2) ? 1 : -1; // increase or decrease relative to the background color\n newColor = adjustLuminance(newColor, adjustBy);\n\n // break if the color reached the limit\n if (channels.every((e) => newColor[e] === 0)) break;\n if (channels.every((e) => newColor[e] === 255)) break;\n }\n //* decrease contrast\n } else if (ratio && contrast > ratio) {\n while (contrastRatio(newColor, color2) > ratio) {\n const adjustBy = !isDark(color2) ? 1 : -1; // increase or decrease relative to the background color\n newColor = adjustLuminance(newColor, adjustBy);\n\n // break if the color reached the limit\n if (channels.every((e) => newColor[e] === 0)) break;\n if (channels.every((e) => newColor[e] === 255)) break;\n }\n }\n\n return returnColorObject(newColor);\n };\n\n return {\n // color conversion\n HEX,\n RGB,\n HSL,\n HWB,\n HSV,\n // color information\n getFormat,\n getRed,\n getGreen,\n getBlue,\n getHue,\n getSaturation,\n getBrightness,\n getLuminance,\n getLuminanceWCAG,\n isDark,\n isLight,\n areColorsEqual,\n contrastRatio,\n\n // color manipulation\n setRed,\n increaseRed,\n decreaseRed,\n\n setGreen,\n increaseGreen,\n decreaseGreen,\n\n setBlue,\n increaseBlue,\n decreaseBlue,\n\n getAlpha,\n setAlpha,\n increaseAlpha,\n decreaseAlpha,\n\n setHue,\n increaseHue,\n decreaseHue,\n spin,\n\n setSaturation,\n saturate,\n desaturate,\n\n setLuminance,\n brighten,\n darken,\n setBrightness,\n increaseBrightness,\n decreaseBrightness,\n\n // color utilities\n blend,\n invert,\n grayscale,\n randomHslColor,\n randomHsvColor,\n randomRgbColor,\n randomHwbColor,\n adjustContrast,\n };\n};\n\ntype ColorKit = ReturnType & {\n /** - Initiates the asynchronous execution of a workletized colorKit function on the UI thread. */\n runOnUI: typeof colorKitUI;\n};\n\nconst colorKit = colorKitUI() as ColorKit;\ncolorKit.runOnUI = colorKitUI;\nexport default colorKit;\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/external/utils/color-kit/index.ts" }, { "path": "registry/native-ui/src/helpers/external/utils/color-kit/types.ts", "content": "/**\n * Color manipulation utilities adapted from reanimated-color-picker\n *\n * Original source: https://github.com/alabsi91/reanimated-color-picker\n * Author: @alabsi91\n * License: MIT\n *\n * This code has been adapted for use in PitsiUI Native with modifications\n * for TypeScript compatibility and integration with the theme system.\n */\n\ntype NAMED_COLORS = {\n readonly aliceblue: \"#f0f8ff\";\n readonly antiquewhite: \"#faebd7\";\n readonly aqua: \"#00ffff\";\n readonly aquamarine: \"#7fffd4\";\n readonly azure: \"#f0ffff\";\n readonly beige: \"#f5f5dc\";\n readonly bisque: \"#ffe4c4\";\n readonly black: \"#000000\";\n readonly blanchedalmond: \"#ffebcd\";\n readonly blue: \"#0000ff\";\n readonly blueviolet: \"#8a2be2\";\n readonly brown: \"#a52a2a\";\n readonly burlywood: \"#deb887\";\n readonly cadetblue: \"#5f9ea0\";\n readonly chartreuse: \"#7fff00\";\n readonly chocolate: \"#d2691e\";\n readonly coral: \"#ff7f50\";\n readonly cornflowerblue: \"#6495ed\";\n readonly cornsilk: \"#fff8dc\";\n readonly crimson: \"#dc143c\";\n readonly cyan: \"#00ffff\";\n readonly darkblue: \"#00008b\";\n readonly darkcyan: \"#008b8b\";\n readonly darkgoldenrod: \"#b8860b\";\n readonly darkgray: \"#a9a9a9\";\n readonly darkgreen: \"#006400\";\n readonly darkgrey: \"#a9a9a9\";\n readonly darkkhaki: \"#bdb76b\";\n readonly darkmagenta: \"#8b008b\";\n readonly darkolivegreen: \"#556b2f\";\n readonly darkorange: \"#ff8c00\";\n readonly darkorchid: \"#9932cc\";\n readonly darkred: \"#8b0000\";\n readonly darksalmon: \"#e9967a\";\n readonly darkseagreen: \"#8fbc8f\";\n readonly darkslateblue: \"#483d8b\";\n readonly darkslategrey: \"#2f4f4f\";\n readonly darkturquoise: \"#00ced1\";\n readonly darkviolet: \"#9400d3\";\n readonly deeppink: \"#ff1493\";\n readonly deepskyblue: \"#00bfff\";\n readonly dimgray: \"#696969\";\n readonly dimgrey: \"#696969\";\n readonly dodgerblue: \"#1e90ff\";\n readonly firebrick: \"#b22222\";\n readonly floralwhite: \"#fffaf0\";\n readonly forestgreen: \"#228b22\";\n readonly fuchsia: \"#ff00ff\";\n readonly gainsboro: \"#dcdcdc\";\n readonly ghostwhite: \"#f8f8ff\";\n readonly gold: \"#ffd700\";\n readonly goldenrod: \"#daa520\";\n readonly gray: \"#808080\";\n readonly green: \"#008000\";\n readonly greenyellow: \"#adff2f\";\n readonly grey: \"#808080\";\n readonly honeydew: \"#f0fff0\";\n readonly hotpink: \"#ff69b4\";\n readonly indianred: \"#cd5c5c\";\n readonly indigo: \"#4b0082\";\n readonly ivory: \"#fffff0\";\n readonly khaki: \"#f0e68c\";\n readonly lavender: \"#e6e6fa\";\n readonly lavenderblush: \"#fff0f5\";\n readonly lawngreen: \"#7cfc00\";\n readonly lemonchiffon: \"#fffacd\";\n readonly lightblue: \"#add8e6\";\n readonly lightcoral: \"#f08080\";\n readonly lightcyan: \"#e0ffff\";\n readonly lightgoldenrodyellow: \"#fafad2\";\n readonly lightgray: \"#d3d3d3\";\n readonly lightgreen: \"#90ee90\";\n readonly lightgrey: \"#d3d3d3\";\n readonly lightpink: \"#ffb6c1\";\n readonly lightsalmon: \"#ffa07a\";\n readonly lightseagreen: \"#20b2aa\";\n readonly lightskyblue: \"#87cefa\";\n readonly lightslategrey: \"#778899\";\n readonly lightsteelblue: \"#b0c4de\";\n readonly lightyellow: \"#ffffe0\";\n readonly lime: \"#00ff00\";\n readonly limegreen: \"#32cd32\";\n readonly linen: \"#faf0e6\";\n readonly magenta: \"#ff00ff\";\n readonly maroon: \"#800000\";\n readonly mediumaquamarine: \"#66cdaa\";\n readonly mediumblue: \"#0000cd\";\n readonly mediumorchid: \"#ba55d3\";\n readonly mediumpurple: \"#9370db\";\n readonly mediumseagreen: \"#3cb371\";\n readonly mediumslateblue: \"#7b68ee\";\n readonly mediumspringgreen: \"#00fa9a\";\n readonly mediumturquoise: \"#48d1cc\";\n readonly mediumvioletred: \"#c71585\";\n readonly midnightblue: \"#191970\";\n readonly mintcream: \"#f5fffa\";\n readonly mistyrose: \"#ffe4e1\";\n readonly moccasin: \"#ffe4b5\";\n readonly navajowhite: \"#ffdead\";\n readonly navy: \"#000080\";\n readonly oldlace: \"#fdf5e6\";\n readonly olive: \"#808000\";\n readonly olivedrab: \"#6b8e23\";\n readonly orange: \"#ffa500\";\n readonly orangered: \"#ff4500\";\n readonly orchid: \"#da70d6\";\n readonly palegoldenrod: \"#eee8aa\";\n readonly palegreen: \"#98fb98\";\n readonly paleturquoise: \"#afeeee\";\n readonly palevioletred: \"#db7093\";\n readonly papayawhip: \"#ffefd5\";\n readonly peachpuff: \"#ffdab9\";\n readonly peru: \"#cd853f\";\n readonly pink: \"#ffc0cb\";\n readonly plum: \"#dda0dd\";\n readonly powderblue: \"#b0e0e6\";\n readonly purple: \"#800080\";\n readonly rebeccapurple: \"#663399\";\n readonly red: \"#ff0000\";\n readonly rosybrown: \"#bc8f8f\";\n readonly royalblue: \"#4169e1\";\n readonly saddlebrown: \"#8b4513\";\n readonly salmon: \"#fa8072\";\n readonly sandybrown: \"#f4a460\";\n readonly seagreen: \"#2e8b57\";\n readonly seashell: \"#fff5ee\";\n readonly sienna: \"#a0522d\";\n readonly silver: \"#c0c0c0\";\n readonly skyblue: \"#87ceeb\";\n readonly slateblue: \"#6a5acd\";\n readonly slategray: \"#708090\";\n readonly snow: \"#fffafa\";\n readonly springgreen: \"#00ff7f\";\n readonly steelblue: \"#4682b4\";\n readonly tan: \"#d2b48c\";\n readonly teal: \"#008080\";\n readonly thistle: \"#d8bfd8\";\n readonly tomato: \"#ff6347\";\n readonly turquoise: \"#40e0d0\";\n readonly violet: \"#ee82ee\";\n readonly wheat: \"#f5deb3\";\n readonly white: \"#ffffff\";\n readonly whitesmoke: \"#f5f5f5\";\n readonly yellow: \"#ffff00\";\n readonly yellowgreen: \"#9acd32\";\n};\n\nexport type ColorFormats =\n | \"hex3\"\n | \"hex4\"\n | \"hex6\"\n | \"hex8\"\n | \"hsl\"\n | \"hsla\"\n | \"rgb\"\n | \"rgba\"\n | \"hsva\"\n | \"hsv\"\n | \"hwba\"\n | \"hwb\";\n\nexport type ColorString = keyof NAMED_COLORS | (string & NonNullable);\n\nexport type rgbaT = { r: number; g: number; b: number; a: number };\nexport type rgbT = Omit;\n\nexport type hslaT = { h: number; s: number; l: number; a: number };\nexport type hslT = Omit;\n\nexport type hsvaT = { h: number; s: number; v: number; a: number };\nexport type hsvT = Omit;\n\nexport type hwbaT = { h: number; w: number; b: number; a: number };\nexport type hwbT = Omit;\n\nexport type SupportedColorFormats =\n | ColorString\n | rgbaT\n | rgbT\n | hslaT\n | hslT\n | hsvaT\n | hsvT\n | hwbaT\n | hwbT\n | number;\n\nexport type ColorTypes = {\n object: (roundValues?: boolean) => T;\n string: (alpha?: boolean) => string;\n array: (roundValues?: boolean) => number[];\n};\n\nexport type ConversionMethods = {\n hex: () => string;\n rgb: () => ColorTypes;\n hsl: () => ColorTypes;\n hsv: () => ColorTypes;\n hwb: () => ColorTypes;\n};\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/external/utils/color-kit/types.ts" }, { "path": "registry/native-ui/src/helpers/external/utils/index.ts", "content": "export * from \"./cn\";\nexport { default as colorKit } from \"./color-kit\";\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/external/utils/index.ts" } ], "categories": [ "native", "react-native", "lib" ], "meta": { "package": "@pitsi-ui/native", "packageSlug": "native-ui", "platform": "native" } }