New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

colorizr

Package Overview
Dependencies
Maintainers
0
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

colorizr - npm Package Compare versions

Comparing version 2.1.1 to 3.0.0-0

dist/index.d.mts

94

package.json
{
"name": "colorizr",
"version": "2.1.1",
"version": "3.0.0-0",
"description": "Manipulate colors like a boss",

@@ -20,50 +20,68 @@ "author": "Gil Barbara <gilbarbara@gmail.com>",

},
"main": "lib/index.js",
"module": "esm/index.js",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js"
}
},
"files": [
"lib",
"esm",
"dist",
"src"
],
"types": "lib/index.d.ts",
"types": "dist/index.d.ts",
"sideEffects": false,
"devDependencies": {
"@gilbarbara/eslint-config": "^0.2.6",
"@gilbarbara/prettier-config": "^0.1.0",
"@gilbarbara/tsconfig": "^0.1.1",
"@size-limit/preset-small-lib": "^8.0.0",
"@types/jest": "^28.1.6",
"husky": "^8.0.1",
"@arethetypeswrong/cli": "^0.16.4",
"@gilbarbara/eslint-config": "^0.8.2",
"@gilbarbara/prettier-config": "^1.0.0",
"@gilbarbara/tsconfig": "^0.2.3",
"@size-limit/preset-small-lib": "^11.1.6",
"@types/node": "^22.8.6",
"@vitest/coverage-v8": "^2.1.4",
"del-cli": "^6.0.0",
"husky": "^9.1.6",
"is-ci-cli": "^2.2.0",
"jest": "^28.1.3",
"jest-watch-typeahead": "^2.0.0",
"repo-tools": "^0.2.2",
"rimraf": "^3.0.2",
"size-limit": "^8.0.0",
"ts-jest": "^28.0.7",
"ts-node": "^10.9.1",
"typescript": "^4.7.4",
"repo-tools": "^0.3.1",
"size-limit": "^11.1.6",
"ts-node": "^10.9.2",
"tsup": "^8.3.5",
"typescript": "^5.6.3",
"vite-tsconfig-paths": "^5.0.1",
"vitest": "^2.1.4",
"watch-run": "^1.2.5"
},
"scripts": {
"build": "npm run clean && npm run build:cjs && npm run build:esm",
"build:cjs": "tsc",
"build:esm": "tsc -m es6 --outDir esm",
"watch:cjs": "npm run build:cjs -- -w",
"watch:esm": "npm run build:esm -- -w",
"clean": "rimraf lib && rimraf esm",
"lint": "eslint --ext .ts,.tsx src test",
"typecheck": "tsc --noEmit -p test/tsconfig.json",
"build": "npm run clean && tsup",
"watch": "tsup --watch",
"clean": "del dist/*",
"lint": "eslint --fix src test",
"typecheck": "tsc -p test/tsconfig.json",
"typevalidation": "attw -P",
"test": "is-ci \"test:coverage\" \"test:watch\"",
"test:coverage": "jest --coverage --bail",
"test:watch": "jest --watchAll --verbose",
"test:coverage": "vitest run --coverage",
"test:watch": "vitest watch",
"format": "prettier \"**/*.{js,jsx,json,yml,yaml,css,less,scss,ts,tsx,md,graphql,mdx}\" --write",
"validate": "npm run lint && npm run typecheck && npm run test:coverage && npm run build && npm run size",
"validate": "npm run lint && npm run typecheck && npm run test:coverage && npm run build && npm run size && npm run typevalidation",
"size": "size-limit",
"prepublishOnly": "npm run validate",
"prepare": "husky install"
"prepare": "husky"
},
"tsup": {
"dts": true,
"entry": [
"src/index.ts"
],
"format": [
"cjs",
"esm"
],
"sourcemap": true,
"splitting": false
},
"eslintConfig": {
"extends": [
"@gilbarbara/eslint-config"
"@gilbarbara/eslint-config/base",
"@gilbarbara/eslint-config/vitest"
],

@@ -77,12 +95,12 @@ "rules": {

{
"name": "lib",
"path": "./lib/index.js",
"limit": "8 kB"
"name": "commonjs",
"path": "./dist/index.js",
"limit": "7.1 kB"
},
{
"name": "esm",
"path": "./esm/index.js",
"limit": "6 kB"
"path": "./dist/index.mjs",
"limit": "7 kB"
}
]
}

@@ -5,9 +5,9 @@ # Colorizr

Color conversion, manipulation, comparison, and analysis.
Color conversion, generation, manipulation, comparison, and analysis.
## Highlights
- 🏖 **Easy to use**: Works with HSL and RGB, including CSS strings
- 🏖 **Easy to use**: Works with Hex, HSL, OkLab, OkLCH, and RGB.
- ♿️ **Accessibility:** WCAG analysis and comparison.
- 🛠 **Small:** Less than 6k (gzipped) and zero dependencies.
- 🛠 **Small:** Less than 7k (gzipped) and tree-shakable.
- 🟦 **Modern:** Written in Typescript.

@@ -31,3 +31,3 @@

Or you can create an instance to access all methods:
Or you can create an instance to use all the methods for the selected color:

@@ -37,20 +37,25 @@ ```typescript

const colorizr = new Colorizr('#ff0044');
const colorInstance = new Colorizr('#ff0044');
colorInstance.luminance; // 0.2168
colorInstance.chroma; // 1
colorInstance.opacity; // 1
```
## Methods
## API
> String inputs accept css values: hex, rgb(a), hsl(a) and named colors.
> String inputs accept css values: hex, hsl, oklab, oklch, rgb, and named colors.
**brightnessDifference(left: string, right: string): number**
_get the brightness difference between 2 colors_
- [Info](#Info)
- [Manipulators](#Manipulators)
- [Utilities](#Utilities)
- [Converters](#Converters)
- [Generators](#Generators)
- [Comparison](#Comparison)
- [Validators](#Validators)
- [Class](#Class)
```typescript
import { brightnessDifference } from 'colorizr';
### Info
brightnessDifference('#fff', 'rgb(255, 0, 68)'); // 171.003
```
**chroma(input: string): number**
_get the chroma of a color_
Get the chroma of a color.

@@ -64,4 +69,227 @@ ```typescript

**luminance(input: string): number**
Get the relative brightness according to the [WCAG definition](https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef).
Normalized to `0` for black and `1` for white.
```typescript
import { luminance } from 'colorizr';
luminance('#ff0044'); // 0.2168
```
**name(input: string): string**
Get the name of a color. Return the hex code if it can't be named.
```typescript
import { name } from 'colorizr';
name('#ffc0cb', 10); // pink
name('rgb(176 224 230)'); // 'powderblue'
name('hsl(344 100 50)'); // #ff0044
```
**opacity(input: string): string**
Get the opacity of a color.
```typescript
import { opacity } from 'colorizr';
opacity('#ff0044'); 1
opacity('rgb(255 0 68 / 90%)'); 0.9
opacity('hsl(344 100 50 / 60%)'); 0.6
```
### Manipulators
**lighten(input: string, alpha: number): string**
Get a color with increased lightness.
```typescript
import { lighten } from 'colorizr';
lighten('#ff0044', 10); // #ff3369
```
**darken(input: string, alpha = 10): string**
Get a color with decreased lightness.
```typescript
import { darken } from 'colorizr';
darken('#ff0044', 10); // #cc0036
```
**saturate(input: string, amount: number): string**
Get a color with increased saturation.
```typescript
import { saturate } from 'colorizr';
saturate('#ff0044', 10); // #ff0044 (already at the maximum)
saturate('pink', 10); // #ffc0cb
```
**desaturate(input: string, alpha: number): string**
Get a color with decreased saturation.
```typescript
import { desaturate } from 'colorizr';
desaturate('#ff0044', 10); // #f20d4a
```
**invert(input: string): string**
Invert the color.
```typescript
import { invert } from 'colorizr';
invert('#07e'); // '#0077ee'
invert('#f058'); // '#ff005588'
```
**rotate(input: string, degrees: number): string**
Get a color with a hue rotated by the specified degrees.
```typescript
import { rotate } from 'colorizr';
rotate('#ff0044', 30); // #ff3b00
```
**opacify(input: string, alpha: number, format?: ColorType): string**
Add opacity to a color
```typescript
import { opacify } from 'colorizr';
opacify('hsl(344, 100, 50)', 10); // rgba(255, 0, 68, 0.9)
opacify('#ff0044', 50); // hsla(344, 100%, 50%, 0.5)
```
**transparentize(input: string, alpha: number, format?: ColorType): string**
Increase/decrease the color opacity.
```typescript
import { transparentize } from 'colorizr';
transparentize('hsl(344, 100, 50)', 10); // rgba(255, 0, 68, 0.9)
transparentize('#ff0044', 50, 'hsl'); // hsla(344, 100%, 50%, 0.5)
```
### Utilities
**addAlphaToHex(input: string, alpha: number): string**
Add an alpha value to a hex string
```typescript
import { addAlphaToHex } from 'colorizr';
addAlphaToHex('#ff0044', 0.9); // '#ff0044e6'
addAlphaToHex('#ff0044cc', 0.9); // '#ff0044e6'
```
**convertAlphaToHex(input: number): string**
Convert an alpha value to a hex value.
```typescript
import { convertAlphaToHex } from 'colorizr';
convertAlphaToHex(0.5); // '80'
```
**extractAlphaFromHex(input: string): number**
Extract the alpha value from a hex string
```typescript
import { extractAlphaFromHex } from 'colorizr';
convertAlphaToHex('#ff004480'); // 0.5
```
**extractColorParts(input: string): ExtractColorPartsReturn**
Extract the color parts from a CSS color string.
Hex colors are not supported.
```typescript
type ExtractColorPartsReturn = {
alpha?: number;
model: 'hsl' | 'oklab' | 'oklch' | 'rgb';
} & Record<string, number>;
extractColorParts('rgb(255 0 68)') // { model: 'rgb', r: 255, g: 0, b: 68 }
extractColorParts('hsl(344 100% 50% / 90%)') // { alpha: 0.9, model: 'hsl', h: 344, g: 100, l: 50 }
```
**formatCSS(input: HSL | RGB, options?: FormatOptions): string**
Get a css string from a color object.
```typescript
import { formatCSS } from 'colorizr';
formatCSS({ h: 344, s: 100, l: 50 }, { format: 'rgb' }); // 'rgb(255, 0, 68)'
formatCSS({ r: 255, g: 0, b: 68 }, { alpha: 0.5, format: 'hsl' }); // 'hsla(344, 100%, 50%, 0.5)'
```
**formatHex(input: string): string**
Format a short hex string of 3 (or 4) digits into 6 (or 8) digits.
```typescript
import { formatHex } from 'colorizr';
formatHex('#07e'); // '#0077ee'
formatHex('#f058'); // '#ff005588'
```
**parseCSS(input: string, format?: ColorType): string | HSL | RGB**
Parse a css string to hex, HSL, OKLAB, OKLCH, or RGB.
If the format isn't set, it will return the same format as the input.
```typescript
import { parseCSS } from 'colorizr';
parseCSS('hsl(344 100% 50%)'); // { h: 344, l: 50, s: 100 }
parseCSS('#ff0044', 'hsl'); // { h: 344, l: 50, s: 100 }
```
**random(): string**
Get a random color.
```typescript
import { random } from 'colorizr';
random(); // '#b385e0'
```
**removeAlphaFromHex(input: string): string**
Remove the alpha value from a hex string
```typescript
import { removeAlphaFromHex } from 'colorizr';
removeAlphaFromHex('#ff0044cc'); // '#ff0044'
```
**textColor(input: string): string**
Get a contrasting color (black or white) for the input color.
```typescript
import { textColor } from 'colorizr';
textColor('#ff0044'); // #ffffff
textColor('#fff800'); // #000000
```
### Comparison
**brightnessDifference(left: string, right: string): number**
Get the brightness difference between the two colors.
```typescript
import { brightnessDifference } from 'colorizr';
brightnessDifference('#fff', 'rgb(255, 0, 68)'); // 171.003
```
**colorDifference(left: string, right: string): number**
_get the color difference between 2 colors_
Get the color difference between the two colors.

@@ -75,3 +303,3 @@ ```typescript

**compare(left: string, right: string): Analysis**
_get the WCAG analysis for two colors_
Get the WCAG analysis between two colors.

@@ -83,3 +311,3 @@ ```typescript

{
({
"brightnessDifference": 171.003,

@@ -93,7 +321,7 @@ "colorDifference": 442,

"normalAAA": false,
}
})
```
**contrast(left: string, right: string): number**
_get the WCAG contrast ratio between 2 colors_
Get the WCAG contrast ratio between two colors.

@@ -105,62 +333,90 @@ ```typescript

```
### Generators
**darken(input: string, amount = 10): string**
_get a color with decreased lightness_
**palette(input: string, options?: PaletteOptions): string[]**
Generate a palette of colors.
```typescript
import { darken } from 'colorizr';
import { palette } from 'colorizr';
darken('#ff0044', 10); // #cc0036
palette('#ff0044');
// ['#ff0044', '#ff7700', '#88ff00', '#00ff77', '#0088ff', '#7700ff'];
palette('#ff0044', { type: 'monochromatic' });
// ['#ff99b4', '#ff5582', '#ff1150', '#cc0036', '#880024', '#440012']
```
**desaturate(input: string, amount: number): string**
_get a color with decreased saturation_
**scheme(input: string, type: Scheme): string[]**
Get a color scheme.
```typescript
import { desaturate } from 'colorizr';
import { scheme } from 'colorizr';
desaturate('#ff0044', 10); // #f20d4a
const complementary = scheme('rgb(255, 0, 68)'); // ['#ff0044', '#00ffbb']
const triadic = scheme('#ff0044', 'triadic'); // ['#ff0044', '#44ff00', '#0044ff']
```
**fade(input: string, amount: number = 10, output?: ColorTypes = 'rgb'): string**
_get a transparent color_
**swatch(input: string, variant?: 'up' | 'down'): string[]**
Generate a color swatch with ten shades.
The `variant` can be used to generate a lighter or darker swatch.
```typescript
import { fade } from 'colorizr';
import { swatch } from 'colorizr';
fade('hsl(344, 100, 50)', 10); // rgba(255, 0, 68, 0.9)
fade('#ff0044', 50, 'hsl'); // hsla(344, 100%, 50%, 0.5)
const colors = swatch('#ff0044');
/* [
"#ffccda",
"#ff99b4",
"#ff668f",
"#ff3369",
"#ff0044",
"#cc0036",
"#990029",
"#66001b",
"#33000e",
"#1a0007",
] */
```
**formatCSS(input: HSL | RGB, options?: FormatOptions): string**
_get the css string for a color model object_
### Converters
**convert(input: string, format: ColorType): string**
Convert a color string from one format to another.
```typescript
import { formatCSS } from 'colorizr';
import { convert } from 'colorizr';
formatCSS({ h: 344, s: 100, l: 50 }, { model: 'rgb' }); // 'rgb(255, 0, 68)'
formatCSS({ r: 255, g: 0, b: 68 }, { alpha: 0.5, model: 'hsl' }); // 'hsla(344, 100%, 50%, 0.5)'
convert('#ff0044', 'hsl') // hsl(344 100% 50%)
convert('rgb(255 0 68)', 'oklch') // oklch(63.269% 0.25404 19.90218)
```
**formatHex(input: string): string**
_format a short hex string of 3 (or 4) digits into 6 (or 8) digits._
**hex2hsl(input: string): HSL**
Convert HEX to HSL.
```typescript
import { formatHex } from 'colorizr';
import { hex2hsl } from 'colorizr';
formatHex('#07e'); // '#0077ee'
formatHex('#f058'); // '#ff005588'
hex2hsl('#ff0044'); // { h: 344, s: 100, l: 50 }
```
**hex2hsl(input: string): HSL**
_convert a hex string into an HSL object_
**hex2oklab(input: string, precision?: number): LAB**
Convert HEX to OKLAB.
```typescript
import { hex2hsl } from 'colorizr';
import { hex2oklab } from 'colorizr';
hex2hsl('#ff0044'); // { h: 344, s: 100, l: 50 }
hex2oklab('#ff0044'); // { l: 0.63269, a: 0.23887, b: 0.08648 }
```
**hex2oklch(input: string, precision?: number): LCH**
Convert HEX to OKLCH.
```typescript
import { hex2oklch } from 'colorizr';
hex2oklch('#ff0044'); // { l: 0.63269, c: 0.25404, h: 19.90218 }
```
**hex2rgb(input: string): RGB**
_convert a hex string into an RGB object_
Convert HEX to RGB.

@@ -173,4 +429,4 @@ ```typescript

**hsl2hex(input: HSL): string**
_convert an HSL object into a hex string_
**hsl2hex(input: HSL | ColorTupple): string**
Convert HSL to HEX.

@@ -181,102 +437,117 @@ ```typescript

hsl2hex({ h: 344, s: 100, l: 50 }); // '#ff0044'
hsl2hex([344, 100, 50]); // '#ff0044'
```
**hsl2rgb(input: HSL): RGB**
_convert an HSL object into an RGB object_
**hsl2oklab(input: HSL | ColorTupple, precision?: number): LAB**
Convert HSL to OKLAB.
```typescript
import { hsl2oklab } from 'colorizr';
hsl2oklab({ h: 344, s: 100, l: 50 }); // { l: 0.63269, a: 0.23887, b: 0.08648 }
hsl2oklab([344, 100, 50]); // { l: 0.63269, a: 0.23887, b: 0.08648 }
```
**hsl2oklch(input: HSL | ColorTupple, precision?: number): string**
Convert HSL to OKLCH.
```typescript
import { hsl2oklch } from 'colorizr';
hsl2oklch({ h: 344, s: 100, l: 50 }); // { l: 0.63269, c: 0.25404, h: 19.90218 }
hsl2oklch([344, 100, 50]); // { l: 0.63269, c: 0.25404, h: 19.90218 }
```
**hsl2rgb(input: HSL | ColorTupple): RGB**
Convert HSL to RGB.
```typescript
import { hsl2rgb } from 'colorizr';
hsl2rgb({ h: 344, s: 100, l: 50 }); // { r: 255, g: 0, b: 68 }
hsl2rgb([344, 100, 50]); // { r: 255, g: 0, b: 68 }
```
**isValidColor(input: any): boolean**
_check if the input can be parsed correctly_
**oklab2hex(input: LAB | ColorTupple): string**
Convert OKLAB to HEX.
```typescript
import { isValidColor } from 'colorizr';
import { oklab2hex } from 'colorizr';
isValidColor('#f04'); // true
isValidColor('#ff0044'); // true
isValidColor('#ff004400'); // true
isValidColor('rgb(100, 255, 0)'); // true
isValidColor('hsla(344, 100%, 50%)'); // true
isValidColor('blue'); // true
isValidColor('aliceblue'); // true
isValidColor('#mmff00'); // false
isValidColor('blue-ish'); // false
oklab2hex({ l: 0.63269, a: 0.23887, b: 0.08648 }); // '#ff0044'
oklab2hex([0.63269, 0.23887, 0.08648]); // '#ff0044'
```
**isValidHex(input: any): boolean**
_check if the input is a valid hex_
**oklab2hsl(input: LAB | ColorTupple): HSL**
Convert OKLAB to HSL.
```typescript
import { isValidHex } from 'colorizr';
import { oklab2hsl } from 'colorizr';
isValidHex('#f04'); // true
oklab2hsl({ l: 0.63269, a: 0.23887, b: 0.08648 }); // { h: 344, s: 100, l: 50 }
oklab2hsl([0.63269, 0.23887, 0.08648]); // { h: 344, s: 100, l: 50 }
```
**lighten(input: string, amount: number): string**
_get a color with increased lightness_
**oklab2oklch(input: LAB | ColorTupple, precision?: number): LCH**
Convert OKLAB to OKLCH.
```typescript
import { lighten } from 'colorizr';
import { oklab2oklch } from 'colorizr';
lighten('#ff0044', 10); // #ff3369
oklab2oklch({ l: 0.63269, a: 0.23887, b: 0.08648 }); // { l: 0.63269, c: 0.25404, h: 19.90218 }
oklab2oklch([0.63269, 0.23887, 0.08648]); // { l: 0.63269, c: 0.25404, h: 19.90218 }
```
**luminance(input: string): number**
_get the relative brightness according to the [WCAG definition](https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef). Normalized to `0` for black and `1` for white._
**oklab2rgb(input: LAB | ColorTupple, precision: number = 0): RGB**
Convert OKLAB to RGB.
```typescript
import { luminance } from 'colorizr';
import { oklab2rgb } from 'colorizr';
luminance('#ff0044'); // 0.2168
oklab2rgb({ l: 0.63269, a: 0.23887, b: 0.08648 }); // { r: 255, g: 0, b: 68 }
oklab2rgb([0.63269, 0.23887, 0.08648]); // { r: 255, g: 0, b: 68 }
```
**name(input: string): string**
_get the named color. return the hex code if it can't be named_
**oklch2hex(input: LCH | ColorTupple): string**
Convert OKLCH to HEX.
```typescript
import { name } from 'colorizr';
import { oklch2hex } from 'colorizr';
name('#ffc0cb', 10); // pink
name('rgb(176, 224, 230)'); // 'powderblue'
name('hsl(344, 100, 50)'); // #ff0044
oklch2hex({ l: 0.63269, c: 0.25404, h: 19.90218 }); // '#ff0044'
oklch2hex([0.63269, 0.25404, 19.90218]); // '#ff0044'
```
**palette(input: string, options?: PaletteOptions): string[]**
_get a palette for a color_
**oklch2hsl(input: LCH | ColorTupple): HSL**
Convert OKLCH to HSL.
```typescript
import { palette } from 'colorizr';
import { oklch2hsl } from 'colorizr';
palette('#ff0044');
// ['#ff0044', '#ff7700', '#88ff00', '#00ff77', '#0088ff', '#7700ff'];
palette('#ff0044', { type: 'monochromatic' });
// ['#ff99b4', '#ff5582', '#ff1150', '#cc0036', '#880024', '#440012']
oklch2hsl({ l: 0.63269, c: 0.25404, h: 19.90218 }); // { h: 344, s: 100, l: 50 }
oklch2hsl([0.63269, 0.25404, 19.90218]); // { h: 344, s: 100, l: 50 }
```
**parseCSS(input: string, output: ColorTypes = 'hex'): string | HSL | RGB**
_parse a css string to hex, hsl, or RGB_
**oklch2oklab(input: LCH | ColorTupple, precision?: number): LAB**
Convert OKLCH to OKLAB.
```typescript
import { parseCSS } from 'colorizr';
import { oklch2oklab } from 'colorizr';
parseCSS('hsl(270 60% 70%)'); // '#b385e0'
parseCSS('#ff0044', 'hsl'); // { h: 344, l: 50, s: 100 }
oklch2oklab({ l: 0.63269, c: 0.25404, h: 19.90218 }); // { l: 0.63269, a: 0.23887, b: 0.08648 }
oklch2oklab([0.63269, 0.25404, 19.90218]); // { l: 0.63269, a: 0.23887, b: 0.08648 }
```
**random(): string**
_get a random color_
**oklch2rgb(input: LCH | ColorTupple, precision: number = 0): RGB**
Convert OKLCH to RGB.
```typescript
import { random } from 'colorizr';
import { oklch2rgb } from 'colorizr';
random(); // '#b385e0'
oklch2rgb({ l: 0.63269, c: 0.25404, h: 19.90218 }); // { r: 255, g: 0, b: 68 }
oklch2rgb([0.63269, 0.25404, 19.90218]); // { r: 255, g: 0, b: 68 }
```
**rgb2hex(input: RGB | RGBArray): string**
_convert an RGB object into a hex string_
**rgb2hex(input: RGB | ColorTupple): string**
Convert RGB to HEX.

@@ -286,8 +557,8 @@ ```typescript

rgb2hex({ r: 255, g: 55, b: 75 }); // '#ff374b'
rgb2hex({ r: 255, g: 0, b: 68 }); // '#ff0044'
rgb2hex([255, 0, 68]); // '#ff0044'
```
**rgb2hsl(input: RGB | RGBArray): HSL**
_convert an RGB object into an HSL object_
**rgb2hsl(input: RGB | ColorTupple): HSL**
Convert RGB to HSL.

@@ -297,47 +568,97 @@ ```typescript

rgb2hsl({ r: 255, g: 55, b: 75 }); // { h: 354, s: 100, l: 60.78 }
rgb2hsl({ r: 255, g: 0, b: 68 }); // { h: 344, s: 100, l: 50 }
rgb2hsl([255, 0, 68]); // { h: 344, s: 100, l: 50 }
```
**rotate(input: string, degrees = 15): string** _get a color with changed hue_
**rgb2oklab(input: RGB | ColorTupple, precision: number): LAB**
Convert RGB to OKLAB.
```typescript
import { rotate } from 'colorizr';
import { rgb2oklab } from 'colorizr';
rotate('#ff0044', 30); // #ff3b00
rgb2oklab({ r: 255, g: 0, b: 68 }); // { l: 0.63269, a: 0.23887, b: 0.08648 }
rgb2oklab([255, 0, 68]); // { l: 0.63269, a: 0.23887, b: 0.08648 }
```
**saturate(input: string, amount: number): string**
_get a color with increased saturation_
**rgb2oklch(input: RGB | ColorTupple, precision: number): LCH**
Convert RGB to OKLCH.
```typescript
import { saturate } from 'colorizr';
import { rgb2oklch } from 'colorizr';
saturate('#ff0044', 10); // #ff0044 (already at the maximum)
saturate('pink', 10); // #ffc0cb
rgb2oklch({ r: 255, g: 0, b: 68 }); // { l: 0.63269, c: 0.25404, h: 19.90218 }
rgb2oklch([255, 0, 68]); // { l: 0.63269, c: 0.25404, h: 19.90218 }
```
**scheme(input: string, type: Scheme): string[]**
_get the scheme for a color_
### Validators
**isValidColor(input: any): boolean**
Check if the input is a valid color.
```typescript
import { scheme } from 'colorizr';
import { isValidColor } from 'colorizr';
const complementary = scheme('rgb(255, 0, 68)'); // ['#ff0044', '#00ffbb']
const triadic = scheme('#ff0044', 'triadic'); // ['#ff0044', '#44ff00', '#0044ff']
isValidColor('#ff0044'); // true
isValidColor('#ff004400'); // true
isValidColor('hsl(136 100% 50%)'); // true
isValidColor('hsla(344, 100%, 50%, 0.4)'); // true
isValidColor('oklab(70.622% 0.1374 0.14283)'); // true
isValidColor('oklch(47.642% 0.29956 274.93693)'); // true
isValidColor('rgb(255 230 109)'); // true
isValidColor('blue'); // true
isValidColor('aliceblue'); // true
isValidColor('#mmff00'); // false
isValidColor('blue-ish'); // false
```
**textColor(input: string): string**
_get a contrasting color to use with the text_
**isHex(input: unknown): boolean**
Check if the input is a valid hex color.
```typescript
import { textColor } from 'colorizr';
import { isHex } from 'colorizr';
textColor('#ff0044'); // #ffffff
textColor('#fff800'); // #000000
isHex('#f04'); // true
isHex('#ff0044'); // true
isHex('#ff0044cc'); // true
```
## Instance API
**isHSL(input: unknown): boolean**
Check if the input is a valid HSL object.
```typescript
import { isHSL } from 'colorizr';
isHSL({ h: 344, s: 100, l: 50 }); // true
```
**isLAB(input: unknown): boolean**
Check if the input is a valid LAB color.
```typescript
import { isLAB } from 'colorizr';
isLAB({ l: 0.63269, a: 0.23887, b: 0.08648 }); // true
```
**isLHC(input: unknown): boolean**
Check if the input is a valid LCH color.
```typescript
import { isLHC } from 'colorizr';
isLHC({ l: 0.63269, c: 0.25404, h: 19.90218 }); // true
```
**isRGB(input: unknown): boolean**
Check if the input is a valid RGB color.
```typescript
import { isRGB } from 'colorizr';
isRGB({ r: 255, g: 0, b: 68 }); // true
```
### Class
```typescript
import Colorizr from 'Colorizr';

@@ -352,63 +673,94 @@

### Getters
#### Getters
**colorizr.hex**
_returns the hex_
Get the hex code.
**colorizr.hsl**
_returns the HSL object_
Get the HSL object.
**colorizr.oklab**
Get the OKLAB object.
**colorizr.oklch**
Get the OKLCH object.
**colorizr.rgb**
_returns the RGB object_
Get the RGB object.
**colorizr.hue**
_returns the color hue, between 0 and 360_
Get the hue (0-360).
**colorizr.saturation**
_returns the color saturation, between 0 and 100_
Get the saturation (0-100).
**colorizr.lightness**
_returns the color lightness, between 0 and 100_
Get the lightness (0-100).
**colorizr.red**
_returns the color red level, between 0 and 255_
Get the red level (0-255).
**colorizr.green**
_returns the color green level, between 0 and 255_
Get the green level (0-255).
**colorizr.blue**
_returns the color blue level, between 0 and 255_
Get the blue level (0-255).
**colorizr.luminance**
**colorizr.chroma**
Get the chroma (0-1).
**colorizr.luminance**
Get the luminance (0-1).
**colorizr.opacity**
Get the opacity (0-1).
**colorizr.css**
Get the css string of the same time as the input.
**colorizr.textColor**
Get a contrasting color (black or white).
### Manipulation
#### Manipulation
**colorizr.lighten(percentage = 10)**
**colorizr.lighten(percentage: number)**
Get a lighter color.
**colorizr.darken(percentage = 10)**
**colorizr.darken(percentage: number)**
Get a darker color.
**colorizr.saturate(percentage = 10)**
**colorizr.desaturate(percentage: number)**
Get a desaturated color.
**colorizr.saturate(percentage = 10)**
**colorizr.saturate(percentage: number)**
Get a saturated color.
**colorizr.rotate(degrees = 15)**
**colorizr.rotate(degrees: number)**
Get a color with a hue rotated.
**colorizr.invert()**
**colorizr.invert()**
Get the inverted color.
**colorizr.fade(percentage = 10)**
**colorizr.transparentize(percentage: number)**
Get a faded color.
### Comparison
#### Comparison
**colorizr.compare(color: string)**
_returns an object with the analysis (check the compare output above)_
Returns an object with the analysis (check the compare format above)
## References
#### Fortmatting
**colorizr.format(type: ColorType, precision?: number)**
Returns the formatted color with the type
## Credits / References
[color.js](https://github.com/color-js/color.js)
[chroma-js](https://gka.github.io/chroma.js/)
[calculating-color-contrast](https://24ways.org/2010/calculating-color-contrast/)
[Colour Contrast Check](https://snook.ca/technical/colour_contrast/colour.html)
[Contrast Checker](https://webaim.org/resources/contrastchecker/)
[Converting Color Spaces in typescript](https://css-tricks.com/converting-color-spaces-in-typescript/)
[Converting Color Spaces in typescript](https://css-tricks.com/converting-color-spaces-in-typescript/)
[A perceptual color space for image processing](https://bottosson.github.io/posts/oklab/)

@@ -1,19 +0,26 @@

import hex2rgb from './hex2rgb';
import { invariant, isString, messages, round } from './modules/utils';
import parseCSS from './parse-css';
import { MESSAGES, PRECISION } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import { round } from '~/modules/utils';
import { isString } from '~/modules/validators';
import parseCSS from '~/parse-css';
/**
* Get the brightness difference between 2 colors.
*/
export default function brightnessDifference(left: string, right: string): number {
invariant(isString(left), messages.left);
invariant(isString(right), messages.right);
export default function brightnessDifference(
left: string,
right: string,
precision = PRECISION,
): number {
invariant(isString(left), MESSAGES.left);
invariant(isString(right), MESSAGES.right);
const RGBLeft = hex2rgb(parseCSS(left));
const RGBRight = hex2rgb(parseCSS(right));
const RGBLeft = parseCSS(left, 'rgb');
const RGBRight = parseCSS(right, 'rgb');
const rightY = (RGBRight.r * 299 + RGBRight.g * 587 + RGBRight.b * 114) / 1000;
const leftY = (RGBLeft.r * 299 + RGBLeft.g * 587 + RGBLeft.b * 114) / 1000;
const brightnessLeft = (RGBLeft.r * 299 + RGBLeft.g * 587 + RGBLeft.b * 114) / 1000;
const brightnessRight = (RGBRight.r * 299 + RGBRight.g * 587 + RGBRight.b * 114) / 1000;
return round(Math.abs(rightY - leftY), 4);
return round(Math.abs(brightnessRight - brightnessLeft), precision);
}

@@ -1,5 +0,8 @@

import hex2rgb from './hex2rgb';
import { invariant, isString, messages, round } from './modules/utils';
import parseCSS from './parse-css';
import { MESSAGES } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import { round } from '~/modules/utils';
import { isString } from '~/modules/validators';
import parseCSS from '~/parse-css';
/**

@@ -9,5 +12,5 @@ * Get the chroma of a color.

export default function chroma(input: string): number {
invariant(isString(input), messages.inputString);
invariant(isString(input), MESSAGES.inputString);
const { r, g, b } = hex2rgb(parseCSS(input));
const { r, g, b } = parseCSS(input, 'rgb');

@@ -14,0 +17,0 @@ const max = Math.max(r, g, b);

@@ -1,5 +0,7 @@

import hex2rgb from './hex2rgb';
import { invariant, isString, messages } from './modules/utils';
import parseCSS from './parse-css';
import { MESSAGES } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import { isString } from '~/modules/validators';
import parseCSS from '~/parse-css';
/**

@@ -9,7 +11,7 @@ * Get the difference between 2 colors.

export default function colorDifference(left: string, right: string): number {
invariant(isString(left), messages.left);
invariant(isString(right), messages.right);
invariant(isString(left), MESSAGES.left);
invariant(isString(right), MESSAGES.right);
const RGBLeft = hex2rgb(parseCSS(left));
const RGBRight = hex2rgb(parseCSS(right));
const RGBLeft = parseCSS(left, 'rgb');
const RGBRight = parseCSS(right, 'rgb');

@@ -16,0 +18,0 @@ return (

@@ -1,7 +0,10 @@

import getBrightnessDifference from './brightness-difference';
import getColorDifference from './color-difference';
import getContrast from './contrast';
import { invariant, isString, messages } from './modules/utils';
import { Analysis } from './types';
import { MESSAGES } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import { isString } from '~/modules/validators';
import getBrightnessDifference from '~/brightness-difference';
import getColorDifference from '~/color-difference';
import getContrast from '~/contrast';
import { Analysis } from '~/types';
/**

@@ -11,4 +14,4 @@ * Check 2 colors for WCAG compliance.

export default function compare(left: string, right: string): Analysis {
invariant(isString(left), messages.left);
invariant(isString(right), messages.right);
invariant(isString(left), MESSAGES.left);
invariant(isString(right), MESSAGES.right);

@@ -15,0 +18,0 @@ const colorThreshold = 500;

@@ -1,5 +0,8 @@

import getLuminance from './luminance';
import { invariant, isString, messages, round } from './modules/utils';
import parseCSS from './parse-css';
import { MESSAGES } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import { round } from '~/modules/utils';
import { isString } from '~/modules/validators';
import getLuminance from '~/luminance';
/**

@@ -9,7 +12,7 @@ * Get the color contrast between 2 colors.

export default function contrast(left: string, right: string): number {
invariant(isString(left), messages.left);
invariant(isString(right), messages.right);
invariant(isString(left), MESSAGES.left);
invariant(isString(right), MESSAGES.right);
const LuminanceLeft = getLuminance(parseCSS(left));
const LuminanceRight = getLuminance(parseCSS(right));
const LuminanceLeft = getLuminance(left);
const LuminanceRight = getLuminance(right);

@@ -16,0 +19,0 @@ return round(

@@ -1,8 +0,10 @@

import updater from './modules/updater';
import updater from '~/modules/updater';
import { Amount, ColorType } from '~/types';
/**
* Decrease color lightness
*/
export default function darken(input: string, amount = 10): string {
return updater('l', '-')(input, amount);
export default function darken(input: string, amount: Amount, format?: ColorType): string {
return updater('l', '-', format)(input, amount);
}

@@ -1,8 +0,10 @@

import updater from './modules/updater';
import updater from '~/modules/updater';
import { Amount, ColorType } from '~/types';
/**
* Decrease color saturation
*/
export default function desaturate(input: string, amount = 10): string {
return updater('s', '-')(input, amount);
export default function desaturate(input: string, amount: Amount, format?: ColorType) {
return updater('s', '-', format)(input, amount);
}

@@ -1,33 +0,95 @@

import hsl2rgb from './hsl2rgb';
import { invariant, isHSL, isNumber, isPlainObject, isRGB, messages } from './modules/utils';
import rgb2Hsl from './rgb2hsl';
import { FormatOptions, HSL, RGB } from './types';
import { MESSAGES, PRECISION } from '~/modules/constants';
import { convertAlphaToHex } from '~/modules/hex-utils';
import { invariant } from '~/modules/invariant';
import { restrictValues, round } from '~/modules/utils';
import { isHex, isHSL, isLAB, isLCH, isValidColorModel } from '~/modules/validators';
export default function formatCSS(input: HSL | RGB, options: FormatOptions = {}): string {
invariant(isPlainObject(input) && (isRGB(input) || isHSL(input)), messages.invalid);
import * as converters from '~/converters';
import { Alpha, ColorModel, ColorType, HEX, HSL } from '~/types';
const { alpha, model = isRGB(input) ? 'rgb' : 'hsl' } = options;
const prefix = `${model}${isNumber(alpha) ? 'a' : ''}`;
let color = input;
export interface FormatOptions {
alpha?: Alpha;
/**
* The output color type.
* @default 'rgb'
*/
format?: ColorType;
/**
* The number of digits of the output.
* @default 5
*/
precision?: number;
/**
* The separator between the values.
* oklab and oklch always use space as a separator.
* @default ' '
*/
separator?: string;
}
export default function formatCSS<T extends ColorModel | HEX>(
input: T,
options: FormatOptions = {},
): string {
invariant(isHex(input) || isValidColorModel(input), MESSAGES.invalid);
const { alpha, format = 'rgb', precision = PRECISION, separator: baseSeparator = ' ' } = options;
let value: HSL;
if (isHex(input)) {
value = converters.hex2hsl(input);
} else if (isHSL(input)) {
value = input;
} else if (isLAB(input)) {
value = converters.oklab2hsl(input);
} else if (isLCH(input)) {
value = converters.oklch2hsl(input);
} else {
value = converters.rgb2hsl(input);
}
const opacity = alpha && alpha !== 1 ? `${round(alpha * 100)}%` : null;
let params = [];
let separator = baseSeparator;
if (model === 'rgb') {
if (isHSL(color)) {
color = hsl2rgb(color);
switch (format) {
case 'hsl': {
const { h, s, l } = value;
params = [h, `${s}%`, `${l}%`];
break;
}
case 'oklab': {
separator = ' ';
const { l, a, b } = restrictValues(converters.hsl2oklab(value), precision);
params = [Math.round(color.r), Math.round(color.g), Math.round(color.b)];
} else {
if (isRGB(color)) {
color = rgb2Hsl(color);
params = [`${round(l * 100, precision)}%`, a, b];
break;
}
case 'oklch': {
separator = ' ';
const { l, c, h } = restrictValues(converters.hsl2oklch(value), precision);
params = [Math.round(color.h), `${Math.round(color.s)}%`, `${Math.round(color.l)}%`];
}
params = [`${round(l * 100, precision)}%`, c, h];
break;
}
case 'rgb': {
const { r, g, b } = converters.hsl2rgb(value);
if (isNumber(alpha)) {
params.push(alpha);
params = [r, g, b];
break;
}
default: {
const hex = converters.hsl2hex(value);
if (alpha && alpha !== 1) {
return `${hex}${convertAlphaToHex(alpha)}`;
}
return hex;
}
}
return `${prefix}(${params.join(', ')})`;
return `${format}(${params.join(separator)}${opacity ? ` / ${opacity}` : ''})`;
}

@@ -1,23 +0,27 @@

import isValidHex from './is-valid-hex';
import { invariant, isString, messages } from './modules/utils';
import { MESSAGES } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import { isHex } from '~/modules/validators';
export default function formatHex(input: string): string {
invariant(isString(input), messages.inputString);
import { HEX } from '~/types';
const color = input.replace('#', '');
let hex = color;
export default function formatHex(input: string): HEX {
invariant(isHex(input), MESSAGES.inputHex);
let color = input.replace('#', '');
if (color.length === 3 || color.length === 4) {
hex = '';
const values = [...color];
[...color].forEach(d => {
hex += d + d;
color = '';
values.forEach(d => {
color += `${d}${d}`;
});
}
hex = `#${hex}`;
const hex = `#${color}`;
invariant(isValidHex(hex), 'invalid hex');
invariant(isHex(hex), 'invalid hex');
return hex;
}

@@ -1,192 +0,36 @@

import chroma from './chroma';
import compare from './compare';
import darken from './darken';
import desaturate from './desaturate';
import fade from './fade';
import formatCSS from './format-css';
import lighten from './lighten';
import luminance from './luminance';
import parseColor from './modules/parse-color';
import { invariant } from './modules/utils';
import rotate from './rotate';
import saturate from './saturate';
import textColor from './text-color';
import { Analysis, HSL, Options, RGB, RGBArray } from './types';
import Colorizr from '~/colorizr';
class Colorizr {
public hex: string;
private readonly model: Options['model'];
public hsl: HSL;
public rgb: RGB;
export { default as brightnessDifference } from '~/brightness-difference';
export { default as chroma } from '~/chroma';
export { default as colorDifference } from '~/color-difference';
export { default as compare } from '~/compare';
export { default as contrast } from '~/contrast';
export { default as convert } from '~/convert';
export { default as darken } from '~/darken';
export { default as desaturate } from '~/desaturate';
export { default as extractColorParts } from '~/extract-color-parts';
export { default as formatCSS } from '~/format-css';
export { default as formatHex } from '~/format-hex';
export { default as isValidColor } from '~/is-valid-color';
export { default as lighten } from '~/lighten';
export { default as luminance } from '~/luminance';
export { default as name } from '~/name';
export { default as palette } from '~/palette';
export { default as opacify } from '~/opacify';
export { default as opacity } from '~/opacity';
export { default as parseCSS } from '~/parse-css';
export { default as random } from '~/random';
export { default as rotate } from '~/rotate';
export { default as saturate } from '~/saturate';
export { default as scheme } from '~/scheme';
export { default as swatch } from '~/swatch';
export { default as textColor } from '~/text-color';
export { default as transparentize } from '~/transparentize';
constructor(color: string | HSL | RGB | RGBArray, options: Options = {}) {
invariant(!!color, 'color is required');
export * from '~/converters';
export * from '~/types';
export * from '~/modules/hex-utils';
export { isHex, isHSL, isLAB, isLCH, isRGB } from '~/modules/validators';
const { model = 'rgb' } = options;
const { hex, hsl, rgb } = parseColor(color);
this.model = model;
this.hex = hex;
this.hsl = hsl;
this.rgb = rgb;
}
/**
* Get css string
*/
get css(): string {
return formatCSS(this.hsl, { model: this.model });
}
/**
* Get the red value
*/
get red(): number {
return Number(this.rgb.r);
}
/**
* Get the green value
*/
get green(): number {
return Number(this.rgb.g);
}
/**
* Get the blue value
*/
get blue(): number {
return Number(this.rgb.b);
}
/**
* Get the hue value
*/
get hue(): number {
return Number(this.hsl.h);
}
/**
* Get the saturation value
*/
get saturation(): number {
return Number(this.hsl.s);
}
/**
* Get the lightness value
*/
get lightness(): number {
return Number(this.hsl.l);
}
/**
* Get the luminance value
*/
get luminance(): number {
return luminance(this.hex);
}
/**
* Get the chroma value
*/
get chroma(): number {
return chroma(this.hex);
}
/**
* Get the contrasted color
*/
get textColor(): string {
return textColor(this.hex);
}
/**
* Test 2 colors for compliance
*/
public compare(input: string): Analysis {
return compare(this.hex, input);
}
/**
* Increase lightness
*/
public lighten(percentage = 10): string {
return lighten(this.hex, percentage);
}
/**
* Decrease lightness
*/
public darken(percentage = 10): string {
return darken(this.hex, percentage);
}
/**
* Increase saturation
*/
public saturate(percentage = 10): string {
return saturate(this.hex, percentage);
}
/**
* Decrease saturation
*/
public desaturate(percentage = 10): string {
return desaturate(this.hex, percentage);
}
/**
* Invert color
*/
public invert(): string {
return rotate(this.hex, 180);
}
/**
* Rotate color
*/
public rotate(degrees = 15): string {
return rotate(this.hex, degrees);
}
/**
* Fade color
*/
public fade(percentage = 10): string {
return fade(this.hex, percentage, this.model);
}
}
export { default as brightnessDifference } from './brightness-difference';
export { default as chroma } from './chroma';
export { default as colorDifference } from './color-difference';
export { default as compare } from './compare';
export { default as contrast } from './contrast';
export { default as darken } from './darken';
export { default as desaturate } from './desaturate';
export { default as fade } from './fade';
export { default as formatCSS } from './format-css';
export { default as formatHex } from './format-hex';
export { default as hex2hsl } from './hex2hsl';
export { default as hex2rgb } from './hex2rgb';
export { default as hsl2hex } from './hsl2hex';
export { default as hsl2rgb } from './hsl2rgb';
export { default as isValidColor } from './is-valid-color';
export { default as isValidHex } from './is-valid-hex';
export { default as lighten } from './lighten';
export { default as luminance } from './luminance';
export { default as name } from './name';
export { default as palette } from './palette';
export { default as parseCSS } from './parse-css';
export { default as random } from './random';
export { default as rgb2hex } from './rgb2hex';
export { default as rgb2hsl } from './rgb2hsl';
export { default as rotate } from './rotate';
export { default as saturate } from './saturate';
export { default as scheme } from './scheme';
export { default as textColor } from './text-color';
export * from './types';
// eslint-disable-next-line unicorn/prefer-export-from
export default Colorizr;

@@ -1,4 +0,4 @@

import parseCSS from './parse-css';
import parseCSS from '~/parse-css';
export default function isValidColor(input: unknown): boolean {
export default function isValidColor(input: string): boolean {
try {

@@ -5,0 +5,0 @@ parseCSS(input);

@@ -1,8 +0,10 @@

import updater from './modules/updater';
import updater from '~/modules/updater';
import { Amount, ColorType } from '~/types';
/**
* Increase color lightness
*/
export default function lighten(input: string, amount = 10): string {
return updater('l', '+')(input, amount);
export default function lighten(input: string, amount: Amount, format?: ColorType) {
return updater('l', '+', format)(input, amount);
}

@@ -1,5 +0,8 @@

import hex2rgb from './hex2rgb';
import { invariant, isString, messages, round } from './modules/utils';
import parseCSS from './parse-css';
import { MESSAGES } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import { round } from '~/modules/utils';
import { isString } from '~/modules/validators';
import parseCSS from '~/parse-css';
/**

@@ -9,5 +12,5 @@ * Get the luminance of a color.

export default function luminance(input: string): number {
invariant(isString(input), messages.inputString);
invariant(isString(input), MESSAGES.inputString);
const { r, g, b } = hex2rgb(parseCSS(input));
const { r, g, b } = parseCSS(input, 'rgb');

@@ -14,0 +17,0 @@ const rgb = [r / 255, g / 255, b / 255];

/**
* CSS named colors
*/
export type CSSColor = keyof typeof cssColors;
export const cssColors = {

@@ -30,3 +33,2 @@ aliceblue: '#f0f8ff',

darkgray: '#a9a9a9',
darkgrey: '#a9a9a9',
darkgreen: '#006400',

@@ -76,6 +78,6 @@ darkkhaki: '#bdb76b',

lightcyan: '#e0ffff',
lightgoldenrodyellow: '#FAFAD2',
lightgoldenrodyellow: '#fafad2',
lightgray: '#d3d3d3',
lightgreen: '#90ee90',
lightgrey: '#d3d3d3',
lightgreen: '#90ee90',
lightpink: '#ffb6c1',

@@ -97,3 +99,3 @@ lightsalmon: '#ffa07a',

mediumorchid: '#ba55d3',
mediumpurple: '#9370d8',
mediumpurple: '#9370db',
mediumseagreen: '#3cb371',

@@ -119,3 +121,3 @@ mediumslateblue: '#7b68ee',

paleturquoise: '#afeeee',
palevioletred: '#d87093',
palevioletred: '#db7093',
papayawhip: '#ffefd5',

@@ -128,2 +130,3 @@ peachpuff: '#ffdab9',

purple: '#800080',
rebeccapurple: '#663399',
red: '#ff0000',

@@ -130,0 +133,0 @@ rosybrown: '#bc8f8f',

@@ -1,2 +0,4 @@

import { invariant, isNumber, round } from './utils';
import { invariant } from '~/modules/invariant';
import { round } from '~/modules/utils';
import { isNumber } from '~/modules/validators';

@@ -3,0 +5,0 @@ /**

@@ -1,15 +0,14 @@

import { invariant, isHSL, isPlainObject, isRGB, isString, limit, messages } from './utils';
import { MESSAGES } from '~/modules/constants';
import { addAlphaToHex } from '~/modules/hex-utils';
import { invariant } from '~/modules/invariant';
import { addAlpha, limit } from '~/modules/utils';
import { isHex, isHSL, isLAB, isLCH, isPlainObject, isRGB, isString } from '~/modules/validators';
import hex2hsl from '../hex2hsl';
import hex2rgb from '../hex2rgb';
import hsl2hex from '../hsl2hex';
import hsl2rgb from '../hsl2rgb';
import isValidHex from '../is-valid-hex';
import parseCSS from '../parse-css';
import rgb2hex from '../rgb2hex';
import rgb2hsl from '../rgb2hsl';
import { Colors, HSL, PlainObject, RGB, RGBArray } from '../types';
import * as converters from '~/converters';
import extractColorParts from '~/extract-color-parts';
import parseCSS from '~/parse-css';
import { Colors, HSL, LAB, LCH, PlainObject, RGB } from '~/types';
export default function parseColor(color: string | HSL | RGB | RGBArray): Colors {
invariant(!!color, messages.input);
export default function parseColor(color: string | HSL | LAB | LCH | RGB): Colors {
invariant(!!color, MESSAGES.input);

@@ -19,33 +18,48 @@ const output: PlainObject = {};

if (isString(color)) {
const hex = parseCSS(color) as string;
const { alpha = 1 } = extractColorParts(color);
const type = isHex(color) ? 'hex' : extractColorParts(color).model;
invariant(isValidHex(hex), 'input is not valid');
output.hex = addAlphaToHex(parseCSS(color, 'hex'), alpha);
output.hsl = addAlpha(parseCSS(color, 'hsl'), alpha);
output.oklab = addAlpha(parseCSS(color, 'oklab'), alpha);
output.oklch = addAlpha(parseCSS(color, 'oklch'), alpha);
output.rgb = addAlpha(parseCSS(color, 'rgb'), alpha);
output.hex = hex;
output.rgb = hex2rgb(hex);
output.hsl = hex2hsl(hex);
} else if (Array.isArray(color)) {
output.rgb = {
r: limit(color[0], 'r'),
g: limit(color[1], 'g'),
b: limit(color[2], 'b'),
};
output.alpha = alpha;
output.type = type;
} else if (isPlainObject(color)) {
const { alpha = 1 } = color;
output.hex = rgb2hex(output.rgb);
output.hsl = rgb2hsl(output.rgb);
} else if (isPlainObject(color)) {
if (isHSL(color)) {
output.hsl = {
h: limit(color.h, 'h'),
s: limit(color.s, 's'),
l: limit(color.l, 'l'),
h: limit(color.h, 'hsl', 'h'),
s: limit(color.s, 'hsl', 's'),
l: limit(color.l, 'hsl', 'l'),
};
output.rgb = hsl2rgb(output.hsl);
output.rgb = converters.hsl2rgb(output.hsl);
output.oklab = converters.hsl2oklab(output.hsl);
output.oklch = converters.hsl2oklch(output.hsl);
output.type = 'hsl';
} else if (isLAB(color)) {
output.hsl = converters.oklab2hsl(color);
output.oklab = color;
output.oklch = converters.oklab2oklch(color);
output.rgb = converters.oklab2rgb(color);
output.type = 'oklab';
} else if (isLCH(color)) {
output.hsl = converters.oklch2hsl(color);
output.oklab = converters.oklch2oklab(color);
output.oklch = color;
output.rgb = converters.oklch2rgb(color);
output.type = 'oklch';
} else if (isRGB(color)) {
output.rgb = {
r: limit(color.r, 'r'),
g: limit(color.g, 'g'),
b: limit(color.b, 'b'),
r: limit(color.r, 'rgb', 'r'),
g: limit(color.g, 'rgb', 'g'),
b: limit(color.b, 'rgb', 'b'),
};
output.hsl = rgb2hsl(output.rgb);
output.hsl = converters.rgb2hsl(output.rgb);
output.oklab = converters.rgb2oklab(output.rgb);
output.oklch = converters.rgb2oklch(output.rgb);
output.type = 'rgb';
} else {

@@ -55,5 +69,11 @@ throw new Error('invalid color');

output.hex = hsl2hex(output.hsl);
output.hex = addAlphaToHex(converters.hsl2hex(output.hsl), alpha);
output.hsl = addAlpha(output.hsl, alpha);
output.oklab = addAlpha(output.oklab, alpha);
output.oklch = addAlpha(output.oklch, alpha);
output.rgb = addAlpha(output.rgb, alpha);
output.alpha = alpha;
} else {
throw new Error(messages.input);
throw new Error(MESSAGES.input);
}

@@ -60,0 +80,0 @@

@@ -1,6 +0,10 @@

import { constrain, invariant, isNumber, isString, messages } from './utils';
import { MESSAGES } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import { clamp } from '~/modules/utils';
import { isHex, isNamedColor, isNumber, isString } from '~/modules/validators';
import hex2hsl from '../hex2hsl';
import parseCSS from '../parse-css';
import { shift } from '../shift';
import extractColorParts from '~/extract-color-parts';
import formatCSS from '~/format-css';
import parseCSS from '~/parse-css';
import { ColorModelKeys, ColorType } from '~/types';

@@ -10,14 +14,22 @@ /**

*/
export default function updater(type: 'h' | 's' | 'l', sign: '+' | '-') {
export default function updater(
key: ColorModelKeys<'hsl'>,
operator: '+' | '-',
format?: ColorType,
) {
return (input: string, amount: number) => {
invariant(isString(input), messages.inputString);
invariant(isNumber(amount), messages.amount);
invariant(isString(input), MESSAGES.inputString);
invariant(isNumber(amount), MESSAGES.alpha);
const hex = parseCSS(input);
const hsl = hex2hsl(hex);
const color = parseCSS(input, 'hsl');
const output = isHex(input) || isNamedColor(input) ? 'hex' : extractColorParts(input).model;
return shift(hex, {
[type]: constrain(hsl[type], amount, [0, 100], sign),
});
return formatCSS(
{
...color,
[key]: clamp(color[key] + (operator === '+' ? amount : -amount), 0, 100),
},
{ format: format ?? output },
);
};
}

@@ -1,29 +0,60 @@

import { HSL, PlainObject, RGB, RGBArray } from '../types';
import { COLOR_KEYS, COLOR_MODELS, MESSAGES, PRECISION } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import {
isHSL,
isLAB,
isLCH,
isNumber,
isPlainObject,
isRGB,
isValidColorModel,
} from '~/modules/validators';
export const HSLKeys = ['h', 's', 'l'];
export const RGBKeys = ['r', 'g', 'b'];
import {
Alpha,
ColorModel,
ColorModelKey,
ColorModelKeys,
ConverterParameters,
LAB,
LCH,
PlainObject,
} from '~/types';
/**
* Constrain value into the range
*/
export function constrain(input: number, amount: number, range: number[], sign: string): number {
invariant(arguments.length === 4, 'All parameters are required');
export function addAlpha<T extends ColorModel>(input: any, alpha?: Alpha): T {
invariant(isValidColorModel(input), MESSAGES.invalid);
const [min, max] = range;
let value = expr(input + sign + amount);
let value = alpha;
if (value < min) {
value = min;
} else if (value > max) {
value = max;
if (!value) {
return input;
}
return Math.abs(value);
/* c8 ignore next 3 */
if (value > 1) {
value /= 100;
}
if (value === 1) {
return input;
}
return { ...input, alpha: value };
}
/**
* Constrain an angle
* Clamp a value between a min and max
* @param value
* @param [min=0] - The minimum value
* @param [max=100] - The maximum value
*/
export function clamp(value: number, min = 0, max = 100) {
return Math.min(Math.max(value, min), max);
}
/**
* Constrain the degrees between 0 and 360
*/
export function constrainDegrees(input: number, amount: number): number {
invariant(isNumber(input), 'input is required');
invariant(isNumber(input), MESSAGES.inputNumber);

@@ -44,211 +75,130 @@ let value = input + amount;

/**
* Parse math string expressions
* Limit values per type.
*/
export function expr(input: string): number {
const chars = [...input];
const n: string[] = [];
const op: string[] = [];
export function limit<TModel extends Extract<ColorModelKey, 'hsl' | 'rgb'>>(
input: number,
model: TModel,
key: ColorModelKeys<TModel>,
): number {
invariant(isNumber(input), 'Input is not a number');
invariant(COLOR_MODELS.includes(model), `Invalid model${model ? `: ${model}` : ''}`);
invariant(COLOR_KEYS[model].includes(key), `Invalid key${key ? `: ${key}` : ''}`);
let parsed;
let index = 0;
let last = true;
switch (model) {
case 'hsl': {
invariant(COLOR_KEYS.hsl.includes(key), 'Invalid key');
n[index] = '';
if (['s', 'l'].includes(key)) {
return clamp(input);
}
// Parse the string
for (const char of chars) {
if (Number.isNaN(parseInt(char, 10)) && char !== '.' && !last) {
op[index] = char;
index++;
n[index] = '';
last = true;
} else {
n[index] += char;
last = false;
return clamp(input, 0, 360);
}
}
case 'rgb': {
invariant(COLOR_KEYS.rgb.includes(key), 'Invalid key');
// Calculate the expression
parsed = parseFloat(n[0]);
for (const [o, element] of op.entries()) {
const value = parseFloat(n[o + 1]);
switch (element) {
case '+':
parsed += value;
break;
case '-':
parsed -= value;
break;
case '*':
parsed *= value;
break;
case '/':
parsed /= value;
break;
default:
break;
return clamp(input, 0, 255);
}
}
return parsed;
}
export function invariant(condition: boolean, message: string): asserts condition {
if (condition) {
return;
}
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
if (message === undefined) {
throw new Error('invariant requires an error message argument');
/* c8 ignore next 3 */
default: {
throw new Error('Invalid inputs');
}
}
let error;
if (!message) {
throw new Error(
'Minified exception occurred; use the non-minified dev environment ' +
'for the full error message and additional helpful warnings.',
);
} else {
error = new Error(message);
}
error.name = 'colorizr';
throw error;
}
/**
* Check if an object contains HSL values
* Parse the input parameters
*/
export function isHSL(input: any): input is HSL {
if (!isPlainObject(input)) {
return false;
}
export function parseInput<T extends ColorModel>(
input: ConverterParameters<T>,
model: ColorModelKey,
): T {
const keys = COLOR_KEYS[model];
const validator = {
hsl: isHSL,
oklab: isLAB,
oklch: isLCH,
rgb: isRGB,
};
const entries = Object.entries(input);
invariant(isPlainObject(input) || Array.isArray(input), MESSAGES.invalid);
return (
!!entries.length &&
entries.every(
([key, value]) => HSLKeys.includes(key) && value >= 0 && value <= (key === 'h' ? 360 : 100),
)
);
}
const value = Array.isArray(input)
? ({ [keys[0]]: input[0], [keys[1]]: input[1], [keys[2]]: input[2] } as unknown as T)
: input;
/**
* Check if the input is a number and not NaN
*/
export function isNumber(input: any): input is number {
return typeof input === 'number' && !Number.isNaN(input);
invariant(validator[model](value), `invalid ${model} color`);
return value;
}
/**
* Check if the input is an object
* Creates an object composed of the picked source properties.
*/
export function isPlainObject(input: any): input is PlainObject {
if (!input) {
return false;
export function pick(input: PlainObject, options: string[]): PlainObject {
if (!Array.isArray(options)) {
throw new TypeError('options must be an array');
}
const { toString } = Object.prototype;
const prototype = Object.getPrototypeOf(input);
return options
.filter(d => typeof input[d] !== 'undefined')
.reduce((acc: PlainObject, d) => {
acc[d] = input[d];
return (
toString.call(input) === '[object Object]' &&
(prototype === null || prototype === Object.getPrototypeOf({}))
);
return acc;
}, {});
}
/**
* Check if an object contains RGB values.
* Restrict the values to a certain number of digits.
*/
export function isRGB(input: any): input is RGB {
if (!isPlainObject(input)) {
return false;
export function restrictValues<T extends LAB | LCH>(
input: T,
precision: number = PRECISION,
forcePrecision = true,
): T {
const output = new Map(Object.entries(input));
for (const [key, value] of output.entries()) {
output.set(key, round(value, precision, forcePrecision));
}
const entries = Object.entries(input);
return (
!!entries.length &&
entries.every(([key, value]) => RGBKeys.includes(key) && value >= 0 && value <= 255)
);
return Object.fromEntries(output) as T;
}
/**
* Check if an array contains RGB values.
* Round decimal numbers.
*/
export function isRGBArray(input: any): input is RGBArray {
return Array.isArray(input) && input.length === 3 && input.every(d => d >= 0 && d <= 255);
}
/**
* Check if the input is a string
*/
export function isString(input: any): input is string {
return typeof input === 'string';
}
/**
* Limit values per type.
*/
export function limit(input: number, type: string): number {
invariant(isNumber(input), 'Input is not a number');
/* istanbul ignore else */
if (RGBKeys.includes(type)) {
return Math.max(Math.min(input, 255), 0);
export function round(input: number, precision = 2, forcePrecision = true): number {
if (!isNumber(input) || input === 0) {
return 0;
}
if (['s', 'l'].includes(type)) {
return Math.max(Math.min(input, 100), 0);
}
if (forcePrecision) {
const factor = 10 ** precision;
if (type === 'h') {
return Math.max(Math.min(input, 360), 0);
return Math.round(input * factor) / factor;
}
throw new Error('Invalid type');
}
const absInput = Math.abs(input);
export const messages = {
amount: 'amount must be a number',
left: 'left is required and must be a string',
right: 'right is required and must be a string',
input: 'input is required',
inputString: 'input is required and must be a string',
invalid: 'invalid input',
options: 'invalid options',
};
let digits = Math.abs(Math.ceil(Math.log(absInput) / Math.LN10));
/**
* Creates an object composed of the picked source properties.
*/
export function pick(input: PlainObject, options: string[]): PlainObject {
if (!Array.isArray(options)) {
throw new TypeError('options must be an array');
if (digits === 0) {
digits = 2;
} else if (digits > precision) {
digits = precision;
}
return options
.filter(d => typeof input[d] !== 'undefined')
.reduce((acc: PlainObject, d) => {
acc[d] = input[d];
let exponent = precision - (digits < 0 ? 0 : digits);
return acc;
}, {});
}
if (exponent <= 1 && precision > 1) {
exponent = 2;
} else if (exponent > precision || exponent === 0) {
exponent = precision;
}
/**
* Round decimal numbers.
*/
export function round(input: number, digits = 2): number {
const factor = 10 ** digits;
const factor = 10 ** exponent;
return Math.round(input * factor) / factor;
}

@@ -1,13 +0,16 @@

import { cssColors } from './modules/css-colors';
import { invariant, isString, messages } from './modules/utils';
import parseCSS from './parse-css';
import { MESSAGES } from '~/modules/constants';
import { cssColors } from '~/modules/css-colors';
import { invariant } from '~/modules/invariant';
import { isString } from '~/modules/validators';
import parseCSS from '~/parse-css';
export default function name(input: string): string {
invariant(isString(input), messages.inputString);
invariant(isString(input), MESSAGES.inputString);
const hex = parseCSS(input);
const hex = parseCSS(input, 'hex');
const [color] = Object.entries(cssColors).find(([, value]) => value === hex) || [];
return color || hex;
return color ?? hex;
}

@@ -1,14 +0,24 @@

import hex2hsl from './hex2hsl';
import hsl2hex from './hsl2hex';
import { invariant, isPlainObject, isString, messages } from './modules/utils';
import parseCSS from './parse-css';
import rotate from './rotate';
import { PaletteOptions } from './types';
import { MESSAGES } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import { isPlainObject, isString } from '~/modules/validators';
import hex2hsl from '~/converters/hex2hsl';
import hsl2hex from '~/converters/hsl2hex';
import parseCSS from '~/parse-css';
import rotate from '~/rotate';
import { HEX } from '~/types';
export interface PaletteOptions {
lightness?: number;
saturation?: number;
size?: number;
type?: string;
}
export default function palette(input: string, options: PaletteOptions = {}): string[] {
invariant(isString(input), messages.inputString);
invariant(isPlainObject(options), messages.options);
invariant(isString(input), MESSAGES.inputString);
invariant(isPlainObject(options), MESSAGES.options);
const { lightness, saturation, size = 6, type } = options;
const hsl = hex2hsl(parseCSS(input));
const hsl = hex2hsl(parseCSS(input, 'hex'));
const output: string[] = [];

@@ -29,8 +39,8 @@

output.push(hsl2hex({ ...hsl, l: lightness || hsl.l, s: saturation || hsl.s }));
output.push(hsl2hex({ ...hsl, l: lightness ?? hsl.l, s: saturation ?? hsl.s }));
for (let index = 1; index < size; index++) {
const color = rotate(input, hsl.h + step * index);
const color = rotate(input, hsl.h + step * index, 'hex') as HEX;
output.push(hsl2hex({ ...hex2hsl(color), l: lightness || hsl.l, s: saturation || hsl.s }));
output.push(hsl2hex({ ...hex2hsl(color), l: lightness ?? hsl.l, s: saturation ?? hsl.s }));
}

@@ -37,0 +47,0 @@

@@ -1,90 +0,146 @@

import hex2hsl from './hex2hsl';
import hex2rgb from './hex2rgb';
import hsl2hex from './hsl2hex';
import hsl2rgb from './hsl2rgb';
import isValidHex from './is-valid-hex';
import { cssColors } from './modules/css-colors';
import { invariant, isString, messages } from './modules/utils';
import rgb2hex from './rgb2hex';
import rgb2hsl from './rgb2hsl';
import { ColorTypes, Return } from './types';
import { MESSAGES, PRECISION } from '~/modules/constants';
import { CSSColor, cssColors } from '~/modules/css-colors';
import { convertAlphaToHex, extractAlphaFromHex, removeAlphaFromHex } from '~/modules/hex-utils';
import { invariant } from '~/modules/invariant';
import { addAlpha, round } from '~/modules/utils';
import { isHex, isNamedColor, isString } from '~/modules/validators';
import * as converters from '~/converters';
import extractColorParts from '~/extract-color-parts';
import { ColorTuple, ColorType, HEX, HSL, LAB, LCH, RGB } from '~/types';
export type ParseCSSReturn<T extends ColorType> = T extends 'hsl'
? HSL
: T extends 'lab'
? LAB
: T extends 'lch'
? LCH
: T extends 'rgb'
? RGB
: T extends 'hex'
? HEX
: never;
/**
* Parse CSS color
*/
export default function parseCSS<T extends ColorTypes = 'hex'>(
input: unknown,
output?: T,
): Return<T> {
invariant(isString(input), messages.inputString);
export default function parseCSS<T extends ColorType>(
input: string,
format?: T,
): ParseCSSReturn<T> {
invariant(isString(input), MESSAGES.inputString);
let result: any;
const parsedInput = cssColors[input.toLowerCase() as keyof typeof cssColors] || input;
const value = isNamedColor(input) ? cssColors[input.toLowerCase() as CSSColor] : input;
if (isValidHex(parsedInput)) {
const output = format ?? (isHex(value) ? 'hex' : extractColorParts(value).model);
const colorParams = (params: Record<string, number>) => Object.values(params) as ColorTuple;
if (isHex(value)) {
const alpha = extractAlphaFromHex(value);
switch (output) {
case 'hsl': {
result = hex2hsl(parsedInput);
result = addAlpha(converters.hex2hsl(value), alpha);
break;
}
case 'oklab': {
result = addAlpha(converters.hex2oklab(value), alpha);
break;
}
case 'oklch': {
result = addAlpha(converters.hex2oklch(value), alpha);
break;
}
case 'rgb': {
result = hex2rgb(parsedInput);
result = addAlpha(converters.hex2rgb(value), alpha);
break;
}
default: {
result = parsedInput;
result = `${removeAlphaFromHex(value)}${alpha !== 1 ? convertAlphaToHex(alpha) : ''}`;
break;
}
}
} else {
// TODO: improve the pattern to require 3 groups
const matches = parsedInput.match(
/(hsl|rgb)a?\((\d+)(?:,\s*|\s+)(\d+)%?(?:,\s*|\s+)(\d+)%?[^)]*\)/i,
);
invariant(Array.isArray(matches), 'invalid CSS string');
invariant(matches.length === 5, 'invalid CSS string');
return result as ParseCSSReturn<T>;
}
const [, model, hORr, sORg, lORb] = matches;
let hex;
let hsl;
let rgb;
switch (output) {
case 'hsl': {
const { alpha, model, ...color } = extractColorParts(value);
if (model === 'hsl') {
hsl = {
h: parseInt(hORr, 10),
s: parseInt(sORg, 10),
l: parseInt(lORb, 10),
};
hex = hsl2hex(hsl);
rgb = hsl2rgb(hsl);
} else {
rgb = {
r: parseInt(hORr, 10),
g: parseInt(sORg, 10),
b: parseInt(lORb, 10),
};
hex = rgb2hex(rgb);
hsl = rgb2hsl(rgb);
if (['oklab', 'oklch'].includes(model) && color.l > 1) {
color.l = round(color.l / 100, PRECISION);
}
result = addAlpha(
model === 'hsl' ? color : converters[`${model}2hsl`](colorParams(color)),
alpha,
);
break;
}
case 'oklab': {
const { alpha, model, ...color } = extractColorParts(value);
switch (output) {
case 'hsl': {
result = hsl;
break;
if (['oklab', 'oklch'].includes(model) && color.l > 1) {
color.l = round(color.l / 100, PRECISION);
}
case 'rgb': {
result = rgb;
break;
result = addAlpha(
model === 'oklab' ? color : converters[`${model}2oklab`](colorParams(color)),
alpha,
);
break;
}
case 'oklch': {
const { alpha, model, ...color } = extractColorParts(value);
if (['oklab', 'oklch'].includes(model) && color.l > 1) {
color.l = round(color.l / 100, PRECISION);
}
case 'hex':
default: {
result = hex;
break;
result = addAlpha(
model === 'oklch' ? color : converters[`${model}2oklch`](colorParams(color)),
alpha,
);
break;
}
case 'rgb': {
const { alpha, model, ...color } = extractColorParts(value);
if (['oklab', 'oklch'].includes(model) && color.l > 1) {
color.l /= 100;
}
result = addAlpha(
model === 'rgb' ? color : converters[`${model}2rgb`](colorParams(color)),
alpha,
);
break;
}
case 'hex':
default: {
const { alpha, model, ...color } = extractColorParts(value);
let alphaPrefix = '';
if (['oklab', 'oklch'].includes(model) && color.l > 1) {
color.l = round(color.l / 100, PRECISION);
}
if (alpha) {
alphaPrefix = convertAlphaToHex(alpha);
}
result = `${converters[`${model}2hex`](colorParams(color))}${alphaPrefix}`;
break;
}
}
return result as Return<T>;
return result as ParseCSSReturn<T>;
}

@@ -1,2 +0,2 @@

import hsl2hex from './hsl2hex';
import hsl2hex from '~/converters/hsl2hex';

@@ -3,0 +3,0 @@ /**

@@ -1,19 +0,29 @@

import hex2hsl from './hex2hsl';
import { constrainDegrees, invariant, isNumber, isString, messages } from './modules/utils';
import parseCSS from './parse-css';
import { shift } from './shift';
import { MESSAGES } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import { constrainDegrees } from '~/modules/utils';
import { isHex, isNamedColor, isNumber, isString } from '~/modules/validators';
import extractColorParts from '~/extract-color-parts';
import formatCSS from '~/format-css';
import parseCSS from '~/parse-css';
import { ColorType, Degrees } from '~/types';
/**
* Change the color hue
*/
export default function rotate(input: string, degrees = 15): string {
invariant(isString(input), messages.inputString);
export default function rotate(input: string, degrees: Degrees, format?: ColorType) {
invariant(isString(input), MESSAGES.inputString);
invariant(isNumber(degrees), 'degrees must be a number');
const hex = parseCSS(input);
const { h } = hex2hsl(hex);
const color = parseCSS(input, 'hsl');
return shift(hex, {
h: constrainDegrees(h, degrees),
});
const output = isHex(input) || isNamedColor(input) ? 'hex' : extractColorParts(input).model;
return formatCSS(
{
...color,
h: constrainDegrees(color.h, degrees),
},
{ format: format ?? output },
);
}

@@ -1,8 +0,10 @@

import updater from './modules/updater';
import updater from '~/modules/updater';
import { ColorType } from '~/types';
/**
* Increase color saturation
*/
export default function saturate(input: string, amount = 10): string {
return updater('s', '+')(input, amount);
export default function saturate(input: string, amount: number, format?: ColorType) {
return updater('s', '+', format)(input, amount);
}

@@ -1,6 +0,9 @@

import { invariant, isString, messages } from './modules/utils';
import parseCSS from './parse-css';
import rotate from './rotate';
import { Scheme } from './types';
import { MESSAGES } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import { isString } from '~/modules/validators';
import parseCSS from '~/parse-css';
import rotate from '~/rotate';
import { Scheme } from '~/types';
/**

@@ -10,5 +13,5 @@ * Get the scheme for a color.

export default function scheme(input: string, type: Scheme = 'complementary'): string[] {
invariant(isString(input), messages.inputString);
invariant(isString(input), MESSAGES.inputString);
const hex = parseCSS(input);
const hex = parseCSS(input, 'hex');
const output: string[] = [];

@@ -15,0 +18,0 @@

@@ -1,15 +0,40 @@

import hex2rgb from './hex2rgb';
import { invariant, isString, messages } from './modules/utils';
import parseCSS from './parse-css';
import { MESSAGES } from '~/modules/constants';
import { invariant } from '~/modules/invariant';
import { isString } from '~/modules/validators';
import hex2rgb from '~/converters/hex2rgb';
import parseCSS from '~/parse-css';
interface Options {
/**
* The dark color to return if the input is light.
* @default '#000000'
*/
darkColor?: string;
/**
* The light color to return if the input is dark.
* @default '#ffffff'
*/
lightColor?: string;
/**
* The threshold to determine if the color is light or dark.
* A number between 0 and 255.
* @default 128
*/
threshold?: number;
}
/**
* Get the contrasted color for a given hex.
*/
export default function textColor(input: string): string {
invariant(isString(input), messages.inputString);
export default function textColor(input: string, options: Options = {}): string {
const { darkColor = '#000000', lightColor = '#ffffff', threshold = 128 } = options;
const { r, g, b } = hex2rgb(parseCSS(input));
invariant(isString(input), MESSAGES.inputString);
invariant(threshold >= 0 && threshold <= 255, MESSAGES.threshold);
const { r, g, b } = hex2rgb(parseCSS(input, 'hex'));
const yiq = (r * 299 + g * 587 + b * 114) / 1000;
return yiq >= 128 ? '#000000' : '#ffffff';
return yiq >= threshold ? darkColor : lightColor;
}

@@ -1,27 +0,46 @@

/* eslint-disable typescript-sort-keys/interface */
export interface Analysis {
brightnessDifference: number;
colorDifference: number;
compliant: number;
contrast: number;
largeAA: boolean;
largeAAA: boolean;
normalAA: boolean;
normalAAA: boolean;
}
/* eslint-disable @typescript-eslint/member-ordering */
export type ColorType = 'hex' | 'hsl' | 'oklab' | 'oklch' | 'rgb';
export type ColorModel = HSL | LAB | LCH | RGB;
export type ColorModelKey = 'hsl' | 'oklab' | 'oklch' | 'rgb';
export type ColorModelKeys<TModel extends ColorModelKey> = TModel extends 'hsl'
? keyof Omit<HSL, 'alpha'>
: TModel extends 'oklab'
? keyof Omit<LAB, 'alpha'>
: TModel extends 'oklch'
? keyof Omit<LCH, 'alpha'>
: TModel extends 'rgb'
? keyof Omit<RGB, 'alpha'>
: never;
export type ColorKeysTuple = [string, string, string];
export type ColorTuple = [number, number, number];
export type ColorTupleWithRound = [number, number, number, boolean];
export type ConverterParameters<TModel extends ColorModel> = TModel | ColorTuple;
export interface Colors {
hex: string;
alpha: Alpha;
hex: HEX;
hsl: HSL;
oklab: LAB;
oklch: LCH;
rgb: RGB;
type: ColorType;
}
export type ColorTypes = 'hex' | 'hsl' | 'rgb';
export type ColorModels = 'hsl' | 'rgb';
/* A number between 0 and 1 */
export type Alpha = number;
export interface FormatOptions {
alpha?: number;
model?: ColorModels;
}
/* A number between 0 and 100 */
export type Amount = number;
/* A number between 0 and 360 */
export type Degrees = number;
/*
Color types
*/
export type HEX = `#${string}`;
export type CSS = `('#' | 'hsl' | 'oklab' | 'oklch' | 'rgb')${string}`;
export interface HSL {

@@ -31,21 +50,19 @@ h: number;

l: number;
alpha?: Alpha;
}
export interface Options {
model?: ColorModels;
export interface LAB {
l: number;
a: number;
b: number;
alpha?: Alpha;
}
export interface PaletteOptions {
lightness?: number;
saturation?: number;
size?: number;
type?: string;
export interface LCH {
l: number;
c: number;
h: number;
alpha?: Alpha;
}
export type PlainObject = Record<string, any>;
type ReturnModel<T> = T extends 'rgb' ? RGB : HSL;
export type Return<T> = T extends 'rgb' | 'hsl' ? ReturnModel<T> : string;
export interface RGB {

@@ -55,6 +72,18 @@ r: number;

b: number;
alpha?: Alpha;
}
export type RGBArray = [number, number, number];
export interface Analysis {
brightnessDifference: number;
colorDifference: number;
compliant: number;
contrast: number;
largeAA: boolean;
largeAAA: boolean;
normalAA: boolean;
normalAAA: boolean;
}
export type PlainObject<T = any> = Record<string, T>;
export type Scheme =

@@ -61,0 +90,0 @@ | 'analogous'

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc