omgovich / colord Goto Github PK
View Code? Open in Web Editor NEWπ A tiny yet powerful tool for high-performance color manipulations and conversions
Home Page: https://colord.omgovich.ru
License: MIT License
π A tiny yet powerful tool for high-performance color manipulations and conversions
Home Page: https://colord.omgovich.ru
License: MIT License
The Harmonies plugin seems to be missing the double split complementary color harmony.
I think it will be a great addition and should be simple to add as it is just a [-30, 0, 30, 150, 210]
rotation array.
The library support saturation and lightness manipulation but not hue. This was quite surprising for me.
I can propose a PR if you're ok with it.
var color = colord({r: 255, g: 255, b: 255, a: 1, hex: "#ffffff"}) // not supported input
If it's supported please tell me if I am doing something wrong here.
I am using colord to make a color picker in react with react-colorful.
I replaced color
with colord
in my project, but found out I don't get the same results, because they treat lighten()
and darken()
differently: While color
shifts color by a fraction of itself, while colord
shifts color by a fraction of whole spectrum.
I prototyped this wrapper to implement this functionality:
import { AnyColor, Colord, HslaColor } from 'colord'
import { colord as nativeColord } from 'colord'
export const clamp = (number: number, min = 0, max = 1): number => {
return number > max ? max : number > min ? number : min
}
export const lightenRelative = (color: AnyColor | Colord, amount: number): HslaColor => {
const hsla = nativeColord(color).toHsl()
return {
h: hsla.h,
s: hsla.s,
l: clamp(hsla.l * (1 + amount), 0, 100),
a: hsla.a
}
}
class ExtendedColord extends Colord {
public lightenRelative(amount: number = 0.1) {
return extendedColord(lightenRelative(this.rgba, amount))
}
public darkenRelative(amount: number = 0.1) {
return extendedColord(lightenRelative(this.rgba, -amount))
}
}
export const extendedColord = (input: AnyColor | Colord): ExtendedColord => {
if (input instanceof ExtendedColord) return input
return new ExtendedColord(input as any)
}
and I will use it for now, but I'd prefer to merge it into the library itself - are you interested in this functionality? I would love to make a PR if so.
Thank you π
colord('hsl(0deg 100% 50%)')
// r { parsed: null, rgba: { r: 0, g: 0, b: 0, a: 1 } }
But works if hue
in number format:
colord('hsl(0 100% 50%)')
// r {
// parsed: { r: 255, g: 0, b: 0, a: 1 },
// rgba: { r: 255, g: 0, b: 0, a: 1 }
// }
I know these are very unlikely patterns to run into, but apparently they exist, so support for them would be nice (but definitely not required):
numbers {
color: rgba(1e2, .5e1, .5e0, +.25e2%);
}
Source: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#rgb_transparency_variations
actual:
const expectValue = '#cc88'
colord(colord(expectValue).toRgbString()).toHex() !== expectValue // #cccc8887
expect:
const expectValue = '#cc88'
colord(colord(expectValue).toRgbString()).toHex() !== expectValue // toHex() return value should equal to expectValue
It would be great if colord could tell me which root colour a given colour falls into for example:
hsl(6, 93%, 71%)
would be grouped under red
hsl(195, 100%, 50%)
would be grouped under blue
hsl(120, 100%, 50%)
would be grouped under green
There could be perhaps 10 colour groups such as red, green, blue, purple, orange, grey, brown, yellow, black, white
syntax could be like colord(#ff0000).toGroup()
colord('rgb(0% 100% 0%)')
// r { parsed: null, rgba: { r: 0, g: 0, b: 0, a: 1 } }
It is the same as rgb(0 255 0)
I think a functional API only with pure functions should be available from a separate package entry point, e.g. colord/pure
or colord/fp
. That approach would also offer seamless extensibility without having to think about the bundling and application of plugins.
I also think that a functional API could complement the currently available chained methods, and the latter could rely upon calling the exported pure functions.
We have something like this in a color picker wheere hue value is changed from a hue slider:
const newColor: HslaColor = {
h: element.value,
s: this.saturation,
l: this.lightness,
a: this.alpha / 100,
};
this.setColor(newColor);
Inside setColor()
function:
setColor(colorString: string | HslaColor) {
const colord = new Colord(colorString);
const { h, s, l, a } = colord.toHsl();
this.hue = h;
this.saturation = s;
this.lightness = l;
this.alpha = this.opacity ? a * 100 : 100;
const hslaColor = colorString as HslaColor;
// Workaround as hue isn't correct after changing hue slider, but Colord parse hue value as zero when color is black.
if (hslaColor && hslaColor.h) {
this.hue = hslaColor.h;
}
this._colord = colord;
...
}
Hue value from HslaColor
object is e.g. 191, but after parsing in to Colord
instance and use toHsl()
it returns a hue of 0
.
I added a workaround if the parameter is an HslaColor
object and then use in this h
property instead, which has the value 191
.
Hello π
I run a security community that finds and fixes vulnerabilities in OSS. A researcher (@GAP-dev) has found a potential issue, which I would be eager to share with you.
Could you add a SECURITY.md
file with an e-mail address for me to send further details to? GitHub recommends a security policy to ensure issues are responsibly disclosed, and it would help direct researchers in the future.
Looking forward to hearing from you π
(cc @huntr-helper)
colord('rgb(29 164 192 / 95%)')
colord('rgb(29 164 192 / 0.95)')
// r {
// parsed: { r: 29, g: 164, b: 192, a: 1 },
// rgba: { r: 29, g: 164, b: 192, a: 1 }
// }
But works with old syntax (with commas):
colord('rgb(29, 164, 192, 0.95)')
// r {
// parsed: { r: 29, g: 164, b: 192, a: 0.95 },
// rgba: { r: 29, g: 164, b: 192, a: 0.95 }
// }
Iβve been trying out a lot of color libraries lately and nothing besides this project came close to the minimalistic approach of color2k. I would love to see some benchmark results for that library when compared to colord.
Hey! Love this library! We're using it to handle a color picker component!
The user has an input to write an hex color in, and then we pass it to colord:
colord('#f00')
We are using the names plugin as well, to let the user input css names:
colord('red')
However we wanted the user to be able to type hex strings without the #
as well, and we're having trouble doing this because we can't just slap #
at the start of the string since the color could be a name as well.
colord('f00') // ==> currently invalid color
Would be awesome if colord would support this usecase as well, maybe with a plugin?
When creating an hsl object with a specific hue, but saturation an lightness set to 0, the hue will also be set to zero
test case:
expect(colord({ h: 50, s: 0, l: 0 }).toHsl().h).toBe(50)
this test will fail and the received result. The expected result is, that the hue stays the same.
First off, great library! Thanks for developing and maintaining it π
I have a feature request:
A utility function for finding the nearest color. Similar to what nearest-color
does, but with TS support and thorough testing.
// example from nearest-color
var colors = {
red: '#f00',
yellow: '#ff0',
blue: '#00f'
};
var nearestColor = require('nearest-color').from(colors);
nearestColor('#800'); // => { name: 'red', value: '#f00', rgb: { r: 255, g: 0, b: 0 }, distance: 119 }
nearestColor('#ffe'); // => { name: 'yellow', value: '#ff0', rgb: { r: 255, g: 255, b: 0 }, distance: 238 }
Do you think it worth implementing? Or is it's irrelevant for your library?
Hi,
I'm no expert in color spaces so what I say might have some knowledge gaps.
Would it be possible to add an option to disable rounding when exporting values ?
I'm working on a postcss plugin similar to postcss-color-mod-function and I have to perform multiple color space conversions that make it lose precision on each conversion.
For example
Starting with an RGB color, converting to HWB to increase blackness, then back to a colord object.
I might misunderstand a few features or not get that they exist but I feel that by doing so I'm losing information in between calculations.
As an example : toHwb()
could have an optional toHwb(rounded?: boolean = true)
argument
I'm ready to contribute that Pull Request if that's something you're interested in.
I recently migrated from tinycolor2 after discovering this awesome library π. However, your library is currently missing a similar API to tinycolor2's getFormat
method , which returns the color format used to create the tinycolor instance. I found this API extremely useful when I try to parse user-inputted color code strings.
It would be great if there is a similar API in your library. For example:
var color = colord("#ff0000");
color.getFormat(); // "hex"
color = colord({ r: 139, g: 200, b: 208, a: 1 });
color.getFormat(); // "rgba"
Thank you very much!
One can manipulate LCH components relative to the current color:
color.rotate(5)
color.lighten(0.1)
color.saturate(0.2)
Of those one can directly set the H
:
color.hue(200)
So why not L
and C
?
color.lightness(80)
color.saturation(35)
Lab/LCH is better than HSL, but also have one problem. When you change C
or H
component for blue color it could change hue to violet.
This issue was fixed in OKLab and OKLCH.
I think we should add it to colord
because it could be winner in upcoming color revolution in CSS.
It is not just a βrandom color spaceβ:
oklab()
and oklch
is part of CSS Colors 4oklab()
and oklch()
support for CSS.oklab()
and oklch()
In CSS you can write hsl like so hsl(0 0% 0% / 0.5)
without the commas or hacing to use hsla
Can this format be supported?
I'm unable to build my app due to an error coming from a dependency that relies on Colord. Any help with this would be appreciated!
When running npm run build
, I get the following error:
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './plugins/names' is not defined by "exports" in ./node_modules/colord/package.json
Hi,
This seems like an awesome library! I'm using Chroma.js right now, but I'm tempted to switch.
One thing I use in Chroma all the time is the color.set()
function. It lets you change a single channel in a color, like: chroma('#036').set('hsl.l', 0.2).hex();
It's not a relative modification like lighten()
and darken()
i Colord.
Is there an equivalent for color.set()
in Colord?
Add a new interface methods for generating color harmonies.
This feature provides an easy way to get good color combinations for the user. For example, to generate accent color or create a color palette on the fly.
The idea is to extend current interface or provide the functionality with a plugin. All methods returns new Colord
instances (if there are more than one, an array of instances).
import { colord } from "colord";
const color = colord("#DC3522");
color()
.analogous()
.map(color => color.toHex()); // -> [ "#dc3522", "#dc2259", "#dc2234", "#dc3522", "#dc5a22", "#dc7F22" ]
color()
.monochromatic();
.map(color => color.toHex()); // -> [ "#dc3522", "#070201", "#320c08", "#5c160e", "#872115", "#b12b1b" ]
color().complimentary(); // -> "#22c9dc"
color()
.splitcomplimentary()
.map(color => color.toHex()); // -> [ "#dc3522", "#22dc92", "#226cdc" ]
color()
.triadic()
.map(color => color.toHex()); // -> [ "#dc3522", "#22dc35", "#3522dc" ]
color()
.tetradic()
.map(color => color.toHex()); // -> [ "#dc3522", "#6cdc22", "#22c9dc", "#9222dc" ]
color()
.rect()
.map(color => color.toHex()); // -> [ "#dc3522", "#c9dc22", "#22c9dc", "3522dc" ]
If the feature looks promising to you, after discussion of API interface and should it be the part of core package or part of the plugin, I would like to implement this feature.
Hi, it is me again :)
Found out about color perceived difference and I was thinking, would it be a good addition for colord
? Seems like it could be used to extend the LAB plugin
.
Hi @omgovich,
In my opinion, the current hex matcher:
const hexMatcher = /^#([0-9a-f]{3,8})$/i;
is a little too generous.
Let's consider the following hex input that a user can provide: #abcde
This matcher will accept it, which is why lines 15-33 exist (to filter out such instances).
if (hex.length <= 4) {
return {
r: parseInt(hex[0] + hex[0], 16),
g: parseInt(hex[1] + hex[1], 16),
b: parseInt(hex[2] + hex[2], 16),
a: hex.length === 4 ? round(parseInt(hex[3] + hex[3], 16) / 255, 2) : 1,
};
}
if (hex.length === 6 || hex.length === 8) {
return {
r: parseInt(hex.substr(0, 2), 16),
g: parseInt(hex.substr(2, 2), 16),
b: parseInt(hex.substr(4, 2), 16),
a: hex.length === 8 ? round(parseInt(hex.substr(6, 2), 16) / 255, 2) : 1,
};
}
return null;
I propose adjusting the matcher to:
const hexMatcher = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
as it is a more rigorous definition & will eliminate the need for an extra condition (one condition will do β is length > 5?)
The TypeScript 4.7 NodeNext
module resolver does not honor the legacy types
property in the package.json
file. You need to add a types
export condition as described here.
Note that the "types" condition should always come first in "exports".
With this change, your package.json
exports should look something like:
{
// ...
"exports": {
".": {
"types": "./index.d.ts", // <-- Add this
"import": "./index.mjs",
"require": "./index.js",
"default": "./index.mjs"
},
"./plugins/a11y": {
"types": "./plugins/a11y.d.ts", // And this
"import": "./plugins/a11y.mjs",
"require": "./plugins/a11y.js",
"default": "./plugins/a11y.mjs"
},
// ...
"./plugins/xyz": {
"types": "./plugins/xyz.d.ts", // etc.
"import": "./plugins/xyz.mjs",
"require": "./plugins/xyz.js",
"default": "./plugins/xyz.mjs"
}
}
}
Thank you for creating this awesome library!
Iβve been using color2kβs hasBadContrast
utility for improving a11y lately. Unfortunately, it doesnβt support specifying a background color by nature, which is a dealbreaker for dark UIs.
Following an upcoming contrast measurement standardβs ideas, I think the contrast utility should have an interface where the desired contrast ratio/standard should be specified first, and then the text and the background color(s) should follow, as explained in the SAPC-APCA contrast standardβs repository.
I have reimplemented mix
plugin in my project by studying your code. API seems so fine and simple thanks to CIE LAB
color space. But I was thinking that I would be very nice to have an ability to mix many colors at once.
Right now I have got two possible scenarios: as new method or separate function just like random()
utility.
I think it would be fine to use an array of objects as arguments:
interface MixtureIngridient {
color: Colord | Input;
ratio: number;
}
mix(colors: MixtureIngridients[]);
But I am not sure what is better option. Am I right that if we implement the utility function approach it should be as separate bundle? And how it is better to implement this size-efficiently? Right now I do not have any idea, if you like the idea of mixing several colors I need some help with correct architecture.
Lab and OKLab can be used to generate colors outside sRGB space. We need methods to control it:
sRGB
, P3
, or Rec.2020
space.See also:
Hi! I have a color picker that should produce the main color and the opposite - contrast color. Right now I use "invert", but it is useless for gray colors and so on.
When trying to import colord
with Vite (via Sveltekit), the bundler throws the following error:
import { colord } from 'colord';
Internal server error: Missing "./package.json" export in "colord" package
Not entirely sure what's going on but on the surface of it it looks like Vite requires access to the package's package.json
for analysis, and since it's not exposed via exports
it's throwing an error
Hi, I am using PixiJs and it uses the '0xFFFFFF' notation. Do colord have this output format? I will .replace('#', '0x') for now, but a built-in way would be interesting.
The a11y plugin doesn't support opacity. It would be great if it did.
Black on white = 21
colord('#000000').contrast('#FFFFFF')
Transparent black on white = 21, even though the text is invisible.
colord('#00000000').contrast('#FFFFFF')
Black on white is readable
colord('#000000').isReadable('#FFFFFF')
Transparent black on white is readable, even though the text is invisible.
colord('#00000000').isReadable('#FFFFFF')
When parsing to name using the plugin, if the color is not exactly the right value the result is undefined
. At user level, it can be expected that the library always return a color name.
colord("#ff0000").toName(); // => red
colord("#fe0000").toName(); // => undefined
If failing to find a perfect match, the lib could search for the closest color. This behavior could also be activated by a parameter to the toName
function.
It would be great if this library could return the colour contrast score in text eg how this other library works:
https://github.com/tmcw/wcag-contrast#score
score(10); // = 'AAA'
Currently you would need to use the isReadable
function to return booleans and manually workout the text score, right?
const aaa = colord("#e60000").isReadable("#ffff47", { level: "AAA" }); // false
const aaaLarge = colord("#e60000").isReadable("#ffff47", { level: "AAA", size: "large" }); // true
if(aaa) return 'AAA'
if(aaaLarge) return 'AAA large'
return 'FAIL'
While building an app using pixi.js using next, storybook and webpack, I encountered the helpful error err Error: Default condition should be last one
emitted as part of the webpack compilation process with no references to files.
Investigating, it was suggested on some github issues it was to do with the order of items in package.json:
"import": {
"default": "./index.mjs",
"types": "./index.d.ts"
}
Instead of the suggested order:
"import": {
"types": "./index.d.ts",
"default": "./index.mjs"
}
I managed to find out that @pixi/color was the culprit, so just followed a hunch and searched every plugin it loadeds source and found colord
. Changing the order of the values in the package.json sorted the issue.
Is this something that can be fixed here? I have no idea of whether this is going to cause other issues, but thought I would ask.
This is probably a lot simpler than I'm trying to make it, so forgive me if this is a dumb question, but how do I darken a colord
by an arbitrary percentage?
myColor = colord("rgb(64, 128, 0)");
expect(myColor.darken(calculation).toRgbString()).toBe("rgb(32, 64, 0)");
In the above example, is there some way to reduce each RGB value by 50% (or any other arbitrary percent?
Add some more utility functions to work with color instances.
Some more simple utilities may be useful for the user:
copy
or clone
: provides an easy way to clone a color instance.equals
: provides an easy way to compare two colors.The are two possibilities as I see:
import { colord } from "colord";
const color = colord("#DC3522");
const anotherColor = colord("#abc123");
const colorCopy = color.copy();
color.equals(colorCopy); // -> true
color.equals(anotherColor); // -> false;
import { colord, copy, equals } from "colord";
const color = colord("#DC3522");
const anotherColor = colord("#abc123");
const colorCopy = copy(color);
equals(colorCopy); // -> true
equals(anotherColor); // -> false;
I think it would be better for this utilities, if they are seems useful for you, to be part of the main interface. In any case, if you think this feature may be useful and should be implemented, I am ready to do this.
First, many thanks for this lib! Tinycolor2 and polished are quite limited, color fits me more but has a bad and narrow minded dev, the rare type we hate to find here on GitHub. This lib is exactly what I've been looking for through those years.
color has this PR open for years, and I would really like to see it on this lib: https://github.com/Qix-/color/pull/141
Here is my use case: I prefer having a white overlay when pressing my buttons, but I can't have this white overlay when the button bg is white / very light. Instead of just isLight(), I would like to ~ "isVeryLight", like isLight(0.8) or some other value pattern.
Can you add it? Thanks!
While itβs a very progressive approach to only offer ESM exports, I think that CommonJS should be supported too via package entry points, e.g. when used in files ran by Node (e.g. for color manipulation inside tailwind.config.js
).
One of my more recent projects offer the following entry points as an example: https://github.com/kripod/otion/blob/18eea38e49d92c86ff8144fecc6404ebac0fa3ac/packages/otion/package.json#L24-L39
When I give an LCH color to the function, I get a different color in the output.
For example this is my color: lch(58.68% 98.6 352.06)
(which is a valid P3 color)
And using toLchString
I expect the same values:
colord('lch(58.68% 98.6 352.06)').toLchString()
But the result is:
lch(56.75% 87.94 348.82)
Here's a live example: https://svelte.dev/repl/14e79bf716994c98956d6b27ae0065a5?version=3.58.0
I know these are very unlikely patterns to run into, but apparently they exist, so support for them would be nice (but definitely not required):
test-angles {
color: hsl(.75turn, 60%, 70%);
color: hsl(4.71239rad, 60%, 70%);
}
Source: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#hsl_syntax_variations
I have a large memory consumption. It starts from a few mb, but goes to a few Gb in about 24h.
β colord.service - Manage, Install and Generate Color Profiles
Loaded: loaded (/lib/systemd/system/colord.service; static)
Active: active (running) since Sat 2023-03-18 17:09:14 CET; 16h ago
Main PID: 1432 (colord)
Tasks: 3 (limit: 18908)
Memory: 1.4G
CPU: 4min 20.780s
CGroup: /system.slice/colord.service
ββ1432 /usr/libexec/colord
I'm one fresh Ubuntu 22.04 (same behaviour on ubuntu 20.04) with a bunch of dockers.
Linux alpxp-nuc 5.15.0-67-generic #74-Ubuntu SMP Wed Feb 22 14:14:39 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
How can I debug what is going on? What logs should I check?
It should be closer to a red shade just like the other libraries do
Took this screenshot while using https://3cg7o.csb.app/
Hi, my open-source buddies!
Unfortunately, my coding skills are way better than my English π
The README became huge and it would be cool if somebody checks and improves the texts there.
@molefrog and @rschristian hope you guys have time to help me a bit π
I ran into an issue where my users could control a color wheel, and control the lightness level separately from hue and saturation. If they were to go absolute white or absolute dark, then they would lose their hue and saturation values. It creates a fairly jarring effect on the app.
Would appreciate some advice.
The export map specifies the types
incorrectly:
Lines 32 to 98 in 3f859e0
You can verify that it's not working by setting compilerOptions.moduleResolution
to Node16
.
It should look closer to:
"exports": {
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
},
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
}
},
Detailed explanation here: microsoft/TypeScript#50067
I think it would be really useful to have an ability to generate monochromatic colors (tints, shades, and tones). You mentioned usefulness of it in #63 and it was on my list of future proposals.
I have already working implementation, it looks like this:
color.tints(5); // generates 5 tint instances of original color;
color.shades(5); // generates 5 shade instances of original color;
color.tones(5); // generates 5 tone instances of original color;
During the prototyping, I have got some questions regarding the API:
color.monochromatic("tones", 5)
or to be a separate methods for each type? I think it would be more readable for this particular case to have different methods.steps
parameter, it gets not so understandable. For example, user wants 3 shades and gets: original color, shade, black. Don't look good.I would like to hear you ideas and suggestions.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.