Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@adobe/leonardo-contrast-colors

Package Overview
Dependencies
Maintainers
22
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@adobe/leonardo-contrast-colors - npm Package Compare versions

Comparing version 1.0.0-alpha.17 to 1.0.0

index.js

42

.eslintrc.json
{
"env": {
"browser": true,
"es6": true
},
"extends": [
"airbnb-base"
],
"parserOptions": {
"ecmaVersion": 12
},
"rules": {
"max-len": "off",
"no-param-reassign": "off",
"no-plusplus": "off",
"object-curly-newline": ["error", { "multiline": true }],
"no-floating-decimal": "off",
"prefer-destructuring": ["error", {"object": true, "array": false}],
"consistent-return": "off",
"no-underscore-dangle": "off",
"no-console": "error",
"camelcase": "off"
}
"env": {
"browser": true,
"es6": true
},
"extends": ["airbnb-base"],
"parserOptions": {
"ecmaVersion": 12
},
"rules": {
"max-len": "off",
"no-param-reassign": "off",
"no-plusplus": "off",
"object-curly-newline": ["error", {"multiline": true}],
"no-floating-decimal": "off",
"prefer-destructuring": ["error", {"object": true, "array": false}],
"consistent-return": "off",
"no-underscore-dangle": "off",
"no-console": "error",
"camelcase": "off"
}
}
# Change Log
## 1.0.0
### Patch Changes
- 342c9ca: \* Migrated from Lerna to Moon for monorepo management.
- Setting up Changeset for release management
- Setting up automated releases on NPM
- Migrate from Jest to Ava for better module support
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.0.0-alpha.17](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.16...@adobe/leonardo-contrast-colors@1.0.0-alpha.17) (2023-01-26)
# [1.0.0-alpha.18](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.17...@adobe/leonardo-contrast-colors@1.0.0-alpha.18) (2023-08-01)
**Note:** Version bump only for package @adobe/leonardo-contrast-colors
# [1.0.0-alpha.17](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.16...@adobe/leonardo-contrast-colors@1.0.0-alpha.17) (2023-01-26)
**Note:** Version bump only for package @adobe/leonardo-contrast-colors
# [1.0.0-alpha.16](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.15...@adobe/leonardo-contrast-colors@1.0.0-alpha.16) (2022-08-12)

@@ -18,6 +27,2 @@

# [1.0.0-alpha.15](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.13...@adobe/leonardo-contrast-colors@1.0.0-alpha.15) (2022-08-09)

@@ -27,39 +32,20 @@

# [1.0.0-alpha.14](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.13...@adobe/leonardo-contrast-colors@1.0.0-alpha.14) (2022-08-09)
### Features
* updated support for APCA with tests and UI ([13251e5](https://github.com/adobe/leonardo/commit/13251e5efdc2e8eef9a536acda2c8d8cb1223945))
- updated support for APCA with tests and UI ([13251e5](https://github.com/adobe/leonardo/commit/13251e5efdc2e8eef9a536acda2c8d8cb1223945))
# [1.0.0-alpha.13](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.12...@adobe/leonardo-contrast-colors@1.0.0-alpha.13) (2022-05-05)
### Bug Fixes
* BackgroundColor length threshold updated to >= ([54fe5e5](https://github.com/adobe/leonardo/commit/54fe5e56d38eaf61c246090090c644caa3b32a59))
- BackgroundColor length threshold updated to >= ([54fe5e5](https://github.com/adobe/leonardo/commit/54fe5e56d38eaf61c246090090c644caa3b32a59))
# [1.0.0-alpha.12](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.11...@adobe/leonardo-contrast-colors@1.0.0-alpha.12) (2021-09-14)
### Bug Fixes
* typo in theme constructor for saturation ([#140](https://github.com/adobe/leonardo/issues/140)) ([beb6d88](https://github.com/adobe/leonardo/commit/beb6d888706f2f5480c1da3c1cb94f16acb65d61))
- typo in theme constructor for saturation ([#140](https://github.com/adobe/leonardo/issues/140)) ([beb6d88](https://github.com/adobe/leonardo/commit/beb6d888706f2f5480c1da3c1cb94f16acb65d61))
# [1.0.0-alpha.11](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.10...@adobe/leonardo-contrast-colors@1.0.0-alpha.11) (2021-09-14)

@@ -69,6 +55,2 @@

# [1.0.0-alpha.10](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.9...@adobe/leonardo-contrast-colors@1.0.0-alpha.10) (2021-09-07)

@@ -78,6 +60,2 @@

# [1.0.0-alpha.9](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.8...@adobe/leonardo-contrast-colors@1.0.0-alpha.9) (2021-08-20)

@@ -87,6 +65,2 @@

# [1.0.0-alpha.8](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.7...@adobe/leonardo-contrast-colors@1.0.0-alpha.8) (2020-09-08)

@@ -96,6 +70,2 @@

# [1.0.0-alpha.7](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.6...@adobe/leonardo-contrast-colors@1.0.0-alpha.7) (2020-08-18)

@@ -105,6 +75,2 @@

# [1.0.0-alpha.6](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.5...@adobe/leonardo-contrast-colors@1.0.0-alpha.6) (2020-08-12)

@@ -114,18 +80,9 @@

# [1.0.0-alpha.5](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.4...@adobe/leonardo-contrast-colors@1.0.0-alpha.5) (2020-05-04)
### Bug Fixes
* ensured smooth is false by default & verified tests passing and UI not impacted by addition ([9722d5b](https://github.com/adobe/leonardo/commit/9722d5b422e60c62243cfae58f21bafbb286854c))
* remove Babel, use ESM wrapper approach for Node 13.x ESM support + CJS support ([#72](https://github.com/adobe/leonardo/issues/72)) ([7541dc1](https://github.com/adobe/leonardo/commit/7541dc1189403039b900ef08ca82023d31063b58))
- ensured smooth is false by default & verified tests passing and UI not impacted by addition ([9722d5b](https://github.com/adobe/leonardo/commit/9722d5b422e60c62243cfae58f21bafbb286854c))
- remove Babel, use ESM wrapper approach for Node 13.x ESM support + CJS support ([#72](https://github.com/adobe/leonardo/issues/72)) ([7541dc1](https://github.com/adobe/leonardo/commit/7541dc1189403039b900ef08ca82023d31063b58))
# [1.0.0-alpha.4](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.3...@adobe/leonardo-contrast-colors@1.0.0-alpha.4) (2020-02-28)

@@ -135,33 +92,18 @@

# [1.0.0-alpha.3](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.2...@adobe/leonardo-contrast-colors@1.0.0-alpha.3) (2020-01-21)
### Bug Fixes
* corrected midtone color outputs ([#46](https://github.com/adobe/leonardo/issues/46)) ([5c780b7](https://github.com/adobe/leonardo/commit/5c780b7a1f0355f985591076a27f1764e1faee3c))
- corrected midtone color outputs ([#46](https://github.com/adobe/leonardo/issues/46)) ([5c780b7](https://github.com/adobe/leonardo/commit/5c780b7a1f0355f985591076a27f1764e1faee3c))
# [1.0.0-alpha.2](https://github.com/adobe/leonardo/compare/@adobe/leonardo-contrast-colors@1.0.0-alpha.1...@adobe/leonardo-contrast-colors@1.0.0-alpha.2) (2019-12-12)
### Bug Fixes
* **contrast-colors:** Add d3 as dependency ([#25](https://github.com/adobe/leonardo/issues/25)) ([34940e0](https://github.com/adobe/leonardo/commit/34940e00f52fa69b413b7c882a79c4d158b19a3b))
- **contrast-colors:** Add d3 as dependency ([#25](https://github.com/adobe/leonardo/issues/25)) ([34940e0](https://github.com/adobe/leonardo/commit/34940e00f52fa69b413b7c882a79c4d158b19a3b))
# 1.0.0-alpha.1 (2019-12-09)
### Features
* added throw error for testing missing parameters ([#90](https://github.com/adobe/leonardo/issues/90)) ([2f5dff7](https://github.com/adobe/leonardo/commit/2f5dff7ced7756ef860ba9e5e661cf5fc1e20a2e))
- added throw error for testing missing parameters ([#90](https://github.com/adobe/leonardo/issues/90)) ([2f5dff7](https://github.com/adobe/leonardo/commit/2f5dff7ced7756ef860ba9e5e661cf5fc1e20a2e))
/*
Copyright 2020 Adobe. All rights reserved.
Copyright 2024 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");

@@ -13,110 +13,611 @@ you may not use this file except in compliance with the License. You may obtain a copy

export as namespace ContrastColors;
export = ContrastColors;
import type ChromaJs from 'chroma-js';
declare namespace ContrastColors {
type InterpolationColorspace = 'CAM02' | 'CAM02p' | 'LCH' | 'LAB' | 'HSL' | 'HSLuv' | 'RGB' | 'HSV';
type Colorspace = 'CAM02' | 'CAM02p' | 'LCH' | 'LAB' | 'HSL' | 'HSLuv' | 'RGB' | 'HSV' | 'HEX';
type RGBArray = number[];
type AdaptiveTheme = (brightness: number, constrast?: number) => AdaptiveTheme | ({
background: string
} | {
name: string,
values: {
name: string,
contrast: number,
value: string
}[]
})[];
type ColorTuple = [number, number, number];
interface ColorScale {
colorKeys: string[],
colorspace: Colorspace,
shift: number,
colors: string[],
scale: ((d: any) => string) | d3.ScaleLinear<number, number>,
colorsHex: string[]
declare module 'chroma-js' {
interface ChromaStatic {
jch(...args: ColorTuple): ChromaJs.Color;
jab(...args: ColorTuple): ChromaJs.Color;
getCSSGradient(
scale: Scale,
/**
* @default 1
*/
length: number,
/**
* @default 90
*/
deg: number,
/**
* @default .005
*/
ε: number
): string;
}
interface NamedColorScale {
name: string,
colorKeys: string[],
colorspace: InterpolationColorspace,
ratios: number[] | { [key: string]: number },
smooth?: boolean
interface Color {
jch(): ColorTuple;
jab(): ColorTuple;
hsluv(): ColorTuple;
}
}
function createScale({
swatches,
colorKeys,
colorspace,
shift,
fullScale,
smooth
}: {
swatches: number,
colorKeys: string[],
colorspace?: InterpolationColorspace,
shift?: number,
fullScale?: boolean,
smooth?: boolean
}): ColorScale | never;
function luminance(r: number, g: number, b: number): number;
function contrast(color: RGBArray, base: RGBArray, baseV: number): number;
function binarySearch(list: number[], value: number, baseLum: number): number;
function generateBaseScale({
colorKeys,
colorspace,
smooth
}: {
colorKeys: string[],
colorspace?: Colorspace,
smooth?: boolean
}): string[];
function generateContrastColors({
colorKeys,
base,
ratios,
colorspace,
smooth,
output
}: {
colorKeys: string[],
base: string,
ratios: number[],
colorspace?: InterpolationColorspace,
smooth?: boolean,
output?: Colorspace
}): string[] | never;
function minPositive(r: number[]): number | never;
function ratioName(r: number[]): number[] | never;
function generateAdaptiveTheme({
colorScales,
baseScale,
brightness,
contrast,
output
}: {
colorScales: NamedColorScale[],
baseScale: string,
brightness?: number,
contrast?: number,
output?: Colorspace,
}): AdaptiveTheme | never;
function fixColorValue(
color: string,
format: Colorspace,
object?: boolean
): string | { [key: string]: number };
}
/**
* Supported colorspaces from the {@link https://www.w3.org/TR/css-color-4/ W3C CSS Color Module Level 4} spec.
* @example '#RRGGBB' // HEX
* @example 'rgb(255 255 255)' // RGB
* @example 'hsl(360deg 0% 100%)' // HSL
* @example 'hsv(360deg 0% 100%)' // HSV
* @example 'hsluv(360 0 100)' // HSLuv
* @example 'lab(100% 0 0)' // LAB
* @example 'lch(100% 0 360deg)' // LCH
* @example 'oklab(100% 0 0)' // OKLAB
* @example 'oklch(100% 0 360deg)' // OKLCH
* @example 'jab(100% 0 0)' // CAM02
* @example 'jch(100% 0 360deg)' // CAM02p
*/
type Colorspace = 'HEX' | 'RGB' | 'HSL' | 'HSV' | 'HSLuv' | 'LAB' | 'LCH' | 'OKLAB' | 'OKLCH' | 'CAM02' | 'CAM02p';
/**
* Supported interpolation colorspaces from the {@link https://www.w3.org/TR/css-color-4/ W3C CSS Color Module Level 4} spec.
* @example 'rgb(255 255 255)' // RGB
* @example 'hsl(360deg 0% 100%)' // HSL
* @example 'hsv(360deg 0% 100%)' // HSV
* @example 'hsluv(360 0 100)' // HSLuv
* @example 'lab(100% 0 0)' // LAB
* @example 'lch(100% 0 360deg)' // LCH
* @example 'oklab(100% 0 0)' // OKLAB
* @example 'oklch(100% 0 360deg)' // OKLCH
* @example 'jab(100% 0 0)' // CAM02
* @example 'jch(100% 0 360deg)' // CAM02p
*/
type InterpolationColorspace = Exclude<Colorspace, 'HEX'>;
type RGBArray = ColorTuple;
interface ColorBase {
/**
* User-defined name for a color, (eg "Blue"). Used to name output color values.
*/
name: string;
/**
* List of specific colors to interpolate between in order to generate a full lightness scale of the color.
* @remarks Strings are passed to {@link ChromaJs.valid}
*/
colorKeys: CssColor[];
/**
* The colorspace in which the key colors will be interpolated.
*/
colorspace?: InterpolationColorspace;
/**
* List of target contrast ratios, or object with named keys for each value.
* @see {@link RatiosArray}, {@link RatiosObject}
*/
ratios: RatiosArray | RatiosObject;
/**
* Applies bezier smoothing to interpolation.
*/
smooth?: boolean;
/**
* Desired color output format.
*/
output?: Colorspace;
saturation?: number;
}
export class Color implements Required<ColorBase> {
constructor({name, colorKeys, colorspace, ratios, smooth, output, saturation}: ColorBase);
name: string;
colorKeys: CssColor[];
colorspace: InterpolationColorspace;
ratios: RatiosArray | RatiosObject;
smooth: boolean;
output: Colorspace;
saturation: number;
readonly colorScale: ChromaJs.Scale;
}
export class BackgroundColor extends Color {
readonly backgroundColorScale: ChromaJs.Scale;
}
/**
* @see {@link https://www.w3.org/TR/WCAG22/#contrast-minimum}
* @see {@link https://www.w3.org/TR/wcag-3.0/#visual-contrast-of-text}
*/
type ContrastFormula = 'wcag2' | 'wcag3';
type LightnessDistribution = 'linear' | 'polynomial';
/**
* Helper function for rounding color values to whole numbers.
*/
export function convertColorValue(
color: string,
format: Colorspace,
/** @default false */
object?: boolean
): number;
export function createScale({
swatches,
colorKeys,
colorspace,
shift,
fullScale,
smooth,
distributeLightness,
sortColor,
asFun
}?: {
/** The number of swatches/steps in the scale. */
swatches: number;
colorKeys: CssColor[];
/**
* The colorspace used to interpolate the color scale.
* @default 'LAB' */
colorspace?: InterpolationColorspace;
/** @default 1 */
shift?: number;
/** @default true */
fullScale?: boolean;
/** @default false */
smooth?: boolean;
/** @default 'linear' */
distributeLightness?: LightnessDistribution;
/** @default true */
sortColor?: boolean;
/** @default false */
asFun?: boolean;
}): ChromaJs.Scale;
export function luminance(r: number, g: number, b: number): number;
export function contrast(
color: RGBArray,
base: RGBArray,
baseV?: number,
/** @default 'wcag2' */
method?: ContrastFormula
): number;
interface UpdateColorOptions extends Partial<ColorBase> {
/**
* The current name of the color to be updated.
*/
color: string;
/**
* A new name for the color.
*/
name?: string;
}
export function minPositive(r: number[], formula: ContrastFormula): number;
export function ratioName(r: number[], formula: ContrastFormula): number[];
export class Theme implements Required<ThemeBase> {
constructor({
colors,
backgroundColor,
lightness,
/**
* @default 1
*/
contrast,
/**
* @default 100
*/
saturation,
/**
* @default 'HEX'
*/
output,
/** @default 'wcag2' */
formula
}: ThemeBase);
colors: Color[];
backgroundColor: BackgroundColor;
lightness: number;
contrast: number;
output: Colorspace;
saturation: number;
formula: ContrastFormula;
readonly backgroundColorValue: number;
/**
* Each color is an object named by user-defined value (eg `name: 'gray'`). `values` array consists of all generated color values for the color, with properties name, contrast, and value.
* @example
* [
{ background: "#e0e0e0" },
{
name: 'gray',
values: [
{name: "gray100", contrast: 1, value: "#e0e0e0"},
{name: "gray200", contrast: 2, value: "#a0a0a0"},
{name: "gray300", contrast: 3, value: "#808080"},
{name: "gray400", contrast: 4.5, value: "#646464"}
]
},
{
name: 'blue',
values: [
{name: "blue100", contrast: 2, value: "#b18cff"},
{name: "blue200", contrast: 3, value: "#8d63ff"},
{name: "blue300", contrast: 4.5, value: "#623aff"},
{name: "blue400", contrast: 8, value: "#1c0ad1"}
]
}
]
*/
readonly contrastColors: [ContrastColorBackground, ...ContrastColor[]];
/**
* Simplified format as an object of key-value pairs. Property is equal to the {@link RatiosArray generated} or {@link RatiosObject user-defined name} for each generated value.
* @example {
* "gray100": "#e0e0e0",
* "gray200": "#a0a0a0",
* "gray300": "#808080",
* "gray400": "#646464",
* "blue100": "#b18cff",
* "blue200": "#8d63ff",
* "blue300": "#623aff",
* "blue400": "#1c0ad1"
* }
*/
readonly contrastColorPairs: Record<string, CssColor>;
/**
* All color values in a flat array.
* @example [ "#e0e0e0", "#a0a0a0", "#808080", "#646464", "#b18cff", "#8d63ff", "#623aff", "#1c0ad1" ]
*/
readonly contrastColorValues: CssColor[];
/**
* Add a {@link Color} to the theme
* @example ```
* const red = new Color({...})
* theme.addColor = red;
* ```
*/
set addColor(arg: Color);
/**
* Remove a {@link Color} from an existing theme. Accepts an object with the Color's name and value, or by passing the Color class itself.
* @example ```
* // Remove via color name
theme.removeColor = {name: 'Red'};
* ```
* @example ```
* // Remove via Color class
* const red = new Color({...})
* theme.removeColor = red;
* ```
*/
set removeColor(arg: Color | {name: string});
/**
* Update a {@link Color} via its setters from the theme. Accepts an object with the name of the color you wish to modify, followed by the property and the new value you wish to modify.
* @example ```
* // Change the colors ratios
* theme.updateColor = {name: 'red', ratios: [3, 4.5, 7]};
* ```
* @example ```
* // Change the colors colorKeys
* theme.updateColor = {name: 'red', colorKeys: ['#ff0000']};
* ```
* @example ```
* // Change the color's name
* theme.updateColor = {name: 'red', name: 'Crimson'};
* ```
*/
set updateColor(arg: UpdateColorOptions | UpdateColorOptions[]);
}
/**
* When passing a flat array of target ratios, the output colors in your Theme will be generated by concatenating the color name (eg "Blue") with numeric increments. Colors with a positive contrast ratio with the base (ie, 2:1) will be named in increments of 100. For example, `gray100`, `gray200`.
*
* Colors with a negative contrast ratio with the base (ie -2:1) will be named in increments less than 100 and based on the number of negative values declared. For example, if there are 3 negative values `[-1.4, -1.3, -1.2, 1, 2, 3]`, the name for those values will be incremented by 100/4 (length plus one to avoid a `0` value), such as `gray25`, `gray50`, and `gray75`.
* @example ```
* new Color({
name: 'blue',
colorKeys: ['#5CDBFF', '#0000FF'],
colorSpace: 'LCH',
ratios: [3, 4.5]
});
// Returns:
[
{
name: 'blue',
values: [
{name: "blue100", contrast: 3, value: "#8d63ff"},
{name: "blue200", contrast: 4.5, value: "#623aff"}
]
}
]
```
*/
type RatiosArray = number[];
/**
* When defining ratios as an object with key-value pairs, you define what name will be output in your Leonardo theme.
* @example ```
* new Color({
name: 'blue',
colorKeys: ['#5CDBFF', '#0000FF'],
colorSpace: 'LCH',
ratios: {
'blue--largeText': 3,
'blue--normalText': 4.5
}
});
// Returns:
[
{
name: 'blue',
values: [
{name: "blue--largeText", contrast: 3, value: "#8d63ff"},
{name: "blue--normalText", contrast: 4.5, value: "#623aff"}
]
}
]
* ```
*/
type RatiosObject = Record<string, number>;
interface ContrastColorBackground {
background: CssColor;
}
interface ContrastColor {
name: string;
values: ContrastColorValue[];
}
interface ContrastColorValue {
name: string;
contrast: number;
value: CssColor;
}
interface ThemeBase {
/**
* List of {@link Color} classes to generate theme colors for.
*/
colors: Color[];
/**
* A single {@link BackgroundColor} class is required.
*/
backgroundColor: BackgroundColor;
/**
* Value from 0-100 for desired lightness of generated theme background color (whole number).
*/
lightness: number;
/**
* Multiplier to increase or decrease contrast for all theme colors.
*/
contrast?: number;
/**
* Value from 0-100 for decreasing saturation of all theme colors.
*/
saturation?: number;
/**
* Desired color output format.
*/
output?: Colorspace;
formula?: ContrastFormula;
}
/**
* A valid CSS color.
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value}
*/
type CssColor = RgbHexColor | RgbColor | HslColor | HsvColor | HsluvColor | LabColor | LchColor | OkLabColor | OkLchColor | Cam02Color | Cam02pColor | CssColorName;
/**
* A string representing a CSS hexadecimal RGB color.
* @example '#ff0000'
* @example '#369'
* @remarks Significantly more permissive than hex colors are, but probably the safest solution given the current limitations of Typescript's string literals.
*/
type RgbHexColor = `#${string}`;
/**
* A CSS RGB color function.
* @example 'rgb(255 255 255)'
*/
type RgbColor = `rgb(${number} ${number} ${number})`;
/**
* A CSS HSL color function.
* @example 'hsl(360deg 0% 100%)'
*/
type HslColor = `hsl(${Degrees} ${Percent} ${Percent})`;
/**
* @example 'hsv(360deg 0% 100%)'
*/
type HsvColor = `hsv(${Degrees} ${Percent} ${Percent})`;
/**
* @example 'hsluv(360 0 100)'
*/
type HsluvColor = `hsluv(${number} ${number} ${number})`;
/**
* @example 'lab(100% 0 0)'
*/
type LabColor = `lab(${Percent} ${number} ${number})`;
/**
* @example 'lch(100% 0 360deg)'
*/
type LchColor = `lch(${Percent} ${number} ${Degrees})`;
/**
* @example 'oklab(100% 0 0)'
*/
type OkLabColor = `oklab(${Percent} ${number} ${number})`;
/**
* @example 'oklch(100% 0 360deg)'
*/
type OkLchColor = `oklch(${Percent} ${number} ${Degrees})`;
/**
* @example 'jab(100% 0 0)'
*/
type Cam02Color = `jab(${Percent} ${number} ${number})`;
/**
* @example 'jch(100% 0 360deg)'
*/
type Cam02pColor = `jch(${Percent} ${number} ${Degrees})`;
type Percent = `${number}%`;
type Degrees = `${number}deg`;
type CssColorName =
| 'aliceblue'
| 'antiquewhite'
| 'aqua'
| 'aquamarine'
| 'azure'
| 'beige'
| 'bisque'
| 'black'
| 'blanchedalmond'
| 'blue'
| 'blueviolet'
| 'brown'
| 'burlywood'
| 'cadetblue'
| 'chartreuse'
| 'chocolate'
| 'coral'
| 'cornflowerblue'
| 'cornsilk'
| 'crimson'
| 'cyan'
| 'darkblue'
| 'darkcyan'
| 'darkgoldenrod'
| 'darkgray'
| 'darkgreen'
| 'darkgrey'
| 'darkkhaki'
| 'darkmagenta'
| 'darkolivegreen'
| 'darkorange'
| 'darkorchid'
| 'darkred'
| 'darksalmon'
| 'darkseagreen'
| 'darkslateblue'
| 'darkslategray'
| 'darkslategrey'
| 'darkturquoise'
| 'darkviolet'
| 'deeppink'
| 'deepskyblue'
| 'dimgray'
| 'dimgrey'
| 'dodgerblue'
| 'firebrick'
| 'floralwhite'
| 'forestgreen'
| 'fuchsia'
| 'gainsboro'
| 'ghostwhite'
| 'goldenrod'
| 'gold'
| 'gray'
| 'green'
| 'greenyellow'
| 'grey'
| 'honeydew'
| 'hotpink'
| 'indianred'
| 'indigo'
| 'ivory'
| 'khaki'
| 'lavenderblush'
| 'lavender'
| 'lawngreen'
| 'lemonchiffon'
| 'lightblue'
| 'lightcoral'
| 'lightcyan'
| 'lightgoldenrodyellow'
| 'lightgray'
| 'lightgreen'
| 'lightgrey'
| 'lightpink'
| 'lightsalmon'
| 'lightseagreen'
| 'lightskyblue'
| 'lightslategray'
| 'lightslategrey'
| 'lightsteelblue'
| 'lightyellow'
| 'lime'
| 'limegreen'
| 'linen'
| 'magenta'
| 'maroon'
| 'mediumaquamarine'
| 'mediumblue'
| 'mediumorchid'
| 'mediumpurple'
| 'mediumseagreen'
| 'mediumslateblue'
| 'mediumspringgreen'
| 'mediumturquoise'
| 'mediumvioletred'
| 'midnightblue'
| 'mintcream'
| 'mistyrose'
| 'moccasin'
| 'navajowhite'
| 'navy'
| 'oldlace'
| 'olive'
| 'olivedrab'
| 'orange'
| 'orangered'
| 'orchid'
| 'palegoldenrod'
| 'palegreen'
| 'paleturquoise'
| 'palevioletred'
| 'papayawhip'
| 'peachpuff'
| 'peru'
| 'pink'
| 'plum'
| 'powderblue'
| 'purple'
| 'rebeccapurple'
| 'red'
| 'rosybrown'
| 'royalblue'
| 'saddlebrown'
| 'salmon'
| 'sandybrown'
| 'seagreen'
| 'seashell'
| 'sienna'
| 'silver'
| 'skyblue'
| 'slateblue'
| 'slategray'
| 'slategrey'
| 'snow'
| 'springgreen'
| 'steelblue'
| 'tan'
| 'teal'
| 'thistle'
| 'tomato'
| 'turquoise'
| 'violet'
| 'wheat'
| 'white'
| 'whitesmoke'
| 'yellow'
| 'yellowgreen';
{
"name": "@adobe/leonardo-contrast-colors",
"version": "1.0.0-alpha.17",
"version": "1.0.0",
"description": "Generate colors based on a desired contrast ratio",

@@ -8,2 +8,3 @@ "repository": "git@github.com:adobe/leonardo.git",

"type": "module",
"types": "./index.d.ts",
"exports": {

@@ -14,25 +15,6 @@ ".": {

},
"jest": {
"moduleFileExtensions": [
"js",
"mjs",
"cjs",
"jsx",
"ts",
"tsx",
"json",
"node"
],
"testMatch": [
"**/__tests__/**/*.m[jt]s?(x)",
"**/?(*.)+(spec|test).m[jt]s?(x)"
]
},
"scripts": {
"dev": "NODE_OPTIONS=--experimental-vm-modules npx jest --watch",
"test": "NODE_OPTIONS=--experimental-vm-modules npx jest"
},
"author": "Nate Baldwin <nbaldwin@adobe.com>",
"license": "Apache-2.0",
"dependencies": {
"apca-w3": "^0.1.9",
"chroma-js": "^2.4.2",

@@ -44,14 +26,7 @@ "ciebase": "^0.1.1",

"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.18.6",
"apca-w3": "^0.1.9",
"colorparsley": "^0.1.8",
"eslint": "^7.32.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-plugin-import": "^2.23.4",
"jest": "^26.6.3"
"ava": "^6.1.1"
},
"publishConfig": {
"access": "public"
},
"gitHead": "efe9cbebfd5720887d91aa116bac86df2b0dbca8"
}
}
}

@@ -9,3 +9,3 @@ # `@adobe/leonardo-contrast-colors`

![Libraries.io dependency status for latest release, scoped npm package](https://img.shields.io/librariesio/release/npm/@adobe/leonardo-contrast-colors) [![license](https://img.shields.io/github/license/adobe/leonardo)](https://github.com/adobe/leonardo/blob/master/LICENSE)
[![Pull requests welcome](https://img.shields.io/badge/PRs-welcome-blueviolet)](https://github.com/adobe/leonardo/blob/master/.github/CONTRIBUTING.md)
[![Pull requests welcome](https://img.shields.io/badge/PRs-welcome-blueviolet)](https://github.com/adobe/leonardo/blob/master/.github/CONTRIBUTING.md)

@@ -27,3 +27,3 @@ This package contains all the functions for generating colors by target contrast ratio.

```js
const { Theme, Color, BackgroundColor } = require('@adobe/leonardo-contrast-colors');
const {Theme, Color, BackgroundColor} = require('@adobe/leonardo-contrast-colors');
```

@@ -34,3 +34,3 @@

```js
import { Theme, Color, BackgroundColor } from '@adobe/leonardo-contrast-colors';
import {Theme, Color, BackgroundColor} from '@adobe/leonardo-contrast-colors';
```

@@ -42,20 +42,24 @@

let gray = new BackgroundColor({
name: 'gray',
colorKeys: ['#cacaca'],
ratios: [2, 3, 4.5, 8]
});
name: 'gray',
colorKeys: ['#cacaca'],
ratios: [2, 3, 4.5, 8]
});
let blue = new Color({
name: 'blue',
colorKeys: ['#5CDBFF', '#0000FF'],
ratios: [3, 4.5]
});
name: 'blue',
colorKeys: ['#5CDBFF', '#0000FF'],
ratios: [3, 4.5]
});
let red = new Color({
name: 'red',
colorKeys: ['#FF9A81', '#FF0000'],
ratios: [3, 4.5]
});
name: 'red',
colorKeys: ['#FF9A81', '#FF0000'],
ratios: [3, 4.5]
});
let theme = new Theme({colors: [gray, blue, red], backgroundColor: gray, lightness: 97});
let theme = new Theme({
colors: [gray, blue, red],
backgroundColor: gray,
lightness: 97
});

@@ -72,26 +76,28 @@ // returns theme colors as JSON

| Parameter | Type | Description |
|-----------|-------|------------|
| `colors` | Array | List of `Color` classes to generate theme colors for. A single `BackgroundColor` class is required. |
| `lightness` | Number | Value from 0-100 for desired lightness of generated theme background color (whole number)|
| `contrast` | Number | Multiplier to increase or decrease contrast for all theme colors (default is `1`) |
| `saturation` | Number | Value from 0-100 for decreasing saturation of all theme colors (default is `100`) |
| `output` | Enum | Desired color output format |
| Parameter | Type | Description |
| ------------ | ------ | --------------------------------------------------------------------------------------------------- |
| `colors` | Array | List of `Color` classes to generate theme colors for. A single `BackgroundColor` class is required. |
| `lightness` | Number | Value from 0-100 for desired lightness of generated theme background color (whole number) |
| `contrast` | Number | Multiplier to increase or decrease contrast for all theme colors (default is `1`) |
| `saturation` | Number | Value from 0-100 for decreasing saturation of all theme colors (default is `100`) |
| `output` | Enum | Desired color output format |
#### Setters
| Setter | Description of output |
|--------|-----------------------|
| `Theme.lightness` | Sets the theme's lightness value |
| `Theme.contrast` | Sets the theme's contrast value |
| `Theme.saturation` | Sets the theme's saturation value |
| `Theme.backgroundColor` | Sets the theme's background color (creates a new `BackgroundColor` if passing a string) |
| `Theme.colors` | Sets colors for theme (must pass `Color`)|
| `Theme.output` | Sets output format for theme |
| [`Theme.addColor`](#themeaddcolor--color) | Add a `Color` to the theme |
| [`Theme.removeColor`](#themeremovecolor--color) | Remove a `Color` from the theme |
| [`Theme.updateColor`](#themeupdatecolor--name-property) | Update a `Color` via its setters from the theme |
| Setter | Description of output |
| ------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| `Theme.lightness` | Sets the theme's lightness value |
| `Theme.contrast` | Sets the theme's contrast value |
| `Theme.saturation` | Sets the theme's saturation value |
| `Theme.backgroundColor` | Sets the theme's background color (creates a new `BackgroundColor` if passing a string) |
| `Theme.colors` | Sets colors for theme (must pass `Color`) |
| `Theme.output` | Sets output format for theme |
| [`Theme.addColor`](#themeaddcolor--color) | Add a `Color` to the theme |
| [`Theme.removeColor`](#themeremovecolor--color) | Remove a `Color` from the theme |
| [`Theme.updateColor`](#themeupdatecolor--name-property) | Update a `Color` via its setters from the theme |
#### `Theme.addColor = color`
Add a `Color` to an existing theme
```js

@@ -104,3 +110,5 @@ const red = new Color({...})

#### `Theme.removeColor = color`
Remove a `Color` from an existing theme. Accepts an object with the `Color`'s name and value, or by passing the `Color` class itself.
```js

@@ -116,3 +124,5 @@ // Remove via color name

#### `Theme.updateColor = {name, property}`
Update a `Color` via its setters from the theme. Accepts an object with the name of the color you wish to modify, followed by the property and the new value you wish to modify.
```js

@@ -131,41 +141,45 @@ const red = new Color({...})

#### Supported output formats:
Available output formats conform to the [W3C CSS Color Module Level 4](https://www.w3.org/TR/css-color-4/) spec for the supported options, as listed below:
| Output option | Sample value |
|---------------|--------------|
| `'HEX'` _(default)_ | `#RRGGBB` |
| `'RGB'` | `rgb(255, 255, 255)` |
| `'HSL'` | `hsl(360deg, 0%, 100%)` |
| `'HSV'` | `hsv(360deg, 0%, 100%)` |
| `'HSLuv'` | `hsluv(360, 0, 100)` |
| `'LAB'` | `lab(100%, 0, 0)` |
| `'LCH'` | `lch(100%, 0, 360deg)` |
| `'CAM02'` | `jab(100%, 0, 0)`|
| `'CAM02p'` | `jch(100%, 0, 360deg)` |
| Output option | Sample value |
| ------------------- | ----------------------- |
| `'HEX'` _(default)_ | `#RRGGBB` |
| `'RGB'` | `rgb(255, 255, 255)` |
| `'HSL'` | `hsl(360deg, 0%, 100%)` |
| `'HSV'` | `hsv(360deg, 0%, 100%)` |
| `'HSLuv'` | `hsluv(360, 0, 100)` |
| `'LAB'` | `lab(100%, 0, 0)` |
| `'LCH'` | `lch(100%, 0, 360deg)` |
| `'CAM02'` | `jab(100%, 0, 0)` |
| `'CAM02p'` | `jch(100%, 0, 360deg)` |
----------
---
### `Color`
### `Color`
Class function used to define colors for a theme. Parameters are destructured and need to be explicitly called.
| Parameter | Type | Description |
|-----------|-------|------|
| `name` | String | User-defined name for a color, (eg "Blue"). Used to name output color values |
| `colorKeys` | Array of strings | List of specific colors to interpolate between in order to generate a full lightness scale of the color. |
| `colorspace` | Enum | The [colorspace](#Supported-interpolation-colorspaces) in which the key colors will be interpolated within. |
| `ratios` | Array or Object | List of target contrast ratios, or object with named keys for each value. |
| `smooth` | Boolean | Applies bezier smoothing to interpolation (false by default) |
| `output` | Enum | Desired color output format |
| Parameter | Type | Description |
| ------------ | ---------------- | ----------------------------------------------------------------------------------------------------------- |
| `name` | String | User-defined name for a color, (eg "Blue"). Used to name output color values |
| `colorKeys` | Array of strings | List of specific colors to interpolate between in order to generate a full lightness scale of the color. |
| `colorspace` | Enum | The [colorspace](#Supported-interpolation-colorspaces) in which the key colors will be interpolated within. |
| `ratios` | Array or Object | List of target contrast ratios, or object with named keys for each value. |
| `smooth` | Boolean | Applies bezier smoothing to interpolation (false by default) |
| `output` | Enum | Desired color output format |
#### Setters
| Setter | Description of output |
|--------|-----------------------|
| `Color.colorKeys` | Sets the color keys |
| Setter | Description of output |
| ------------------ | --------------------------------- |
| `Color.colorKeys` | Sets the color keys |
| `Color.colorspace` | Sets the interpolation colorspace |
| `Color.ratios` | Sets the ratios |
| `Color.name` | Sets the name |
| `Color.smooth` | Sets the smoothing option |
| `Color.output` | Sets the output format |
| `Color.ratios` | Sets the ratios |
| `Color.name` | Sets the name |
| `Color.smooth` | Sets the smoothing option |
| `Color.output` | Sets the output format |
#### Supported interpolation colorspaces:
Below are the available options for interpolation in Leonardo:

@@ -182,2 +196,3 @@

#### Ratios as an array
When passing a flat array of target ratios, the output colors in your Theme will be generated by concatenating the color name (eg "Blue") with numeric increments. Colors with a **positive contrast ratio** with the base (ie, 2:1) will be named in increments of 100. For example, `gray100`, `gray200`.

@@ -188,2 +203,3 @@

For example:
```js

@@ -202,11 +218,13 @@ new Color({

values: [
{name: "blue100", contrast: 3, value: "#8d63ff"},
{name: "blue200", contrast: 4.5, value: "#623aff"}
{name: 'blue100', contrast: 3, value: '#8d63ff'},
{name: 'blue200', contrast: 4.5, value: '#623aff'}
]
}
]
];
```
#### Ratios as an object
When defining ratios as an object with key-value pairs, you define what name will be output in your Leonardo theme.
```js

@@ -228,7 +246,7 @@ new Color({

values: [
{name: "blue--largeText", contrast: 3, value: "#8d63ff"},
{name: "blue--normalText", contrast: 4.5, value: "#623aff"}
{name: 'blue--largeText', contrast: 3, value: '#8d63ff'},
{name: 'blue--normalText', contrast: 4.5, value: '#623aff'}
]
}
]
];
```

@@ -239,2 +257,3 @@

## Output examples
There are two types of output you can get from the `Theme` class:

@@ -247,4 +266,4 @@ | Getter | Description of output |

### `Theme.contrastColors`
### `Theme.contrastColors`
Each color is an object named by user-defined value (eg `name: 'gray'`). "Values" array consists of all generated color values for the color, with properties `name`, `contrast`, and `value`:

@@ -254,10 +273,10 @@

[
{ background: "#e0e0e0" },
{background: '#e0e0e0'},
{
name: 'gray',
values: [
{name: "gray100", contrast: 1, value: "#e0e0e0"},
{name: "gray200", contrast: 2, value: "#a0a0a0"},
{name: "gray300", contrast: 3, value: "#808080"},
{name: "gray400", contrast: 4.5, value: "#646464"}
{name: 'gray100', contrast: 1, value: '#e0e0e0'},
{name: 'gray200', contrast: 2, value: '#a0a0a0'},
{name: 'gray300', contrast: 3, value: '#808080'},
{name: 'gray400', contrast: 4.5, value: '#646464'}
]

@@ -268,12 +287,13 @@ },

values: [
{name: "blue100", contrast: 2, value: "#b18cff"},
{name: "blue200", contrast: 3, value: "#8d63ff"},
{name: "blue300", contrast: 4.5, value: "#623aff"},
{name: "blue400", contrast: 8, value: "#1c0ad1"}
{name: 'blue100', contrast: 2, value: '#b18cff'},
{name: 'blue200', contrast: 3, value: '#8d63ff'},
{name: 'blue300', contrast: 4.5, value: '#623aff'},
{name: 'blue400', contrast: 8, value: '#1c0ad1'}
]
}
]
];
```
### `Theme.contrastColorPairs`
Simplified format as an object of key-value pairs. Property is equal to the [generated](#Ratios-as-an-array) or [user-defined name](#Ratios-as-an-object) for each generated value.

@@ -295,15 +315,7 @@

### `Theme.contrastColorValues`
Returns all color values in a flat array.
```js
[
"#e0e0e0",
"#a0a0a0",
"#808080",
"#646464",
"#b18cff",
"#8d63ff",
"#623aff",
"#1c0ad1"
]
['#e0e0e0', '#a0a0a0', '#808080', '#646464', '#b18cff', '#8d63ff', '#623aff', '#1c0ad1'];
```

@@ -314,5 +326,7 @@

## Leonardo with CSS variables
Here are a few examples of how you can utilize Leonardo to dynamically create or modify CSS variables for your application.
### Vanilla JS
```js

@@ -324,3 +338,3 @@ let varPrefix = '--';

// Iterate each value object within each color object
for(let j = 0; j < myTheme[i].values.length; j++) {
for (let j = 0; j < myTheme[i].values.length; j++) {
// output "name" of color and prefix

@@ -332,4 +346,3 @@ let key = myTheme[i].values[j].name;

// create CSS property with name and value
document.documentElement.style
.setProperty(prop, value);
document.documentElement.style.setProperty(prop, value);
}

@@ -340,7 +353,9 @@ }

### React
Create a new Theme component `Theme.js` with your parameters:
```js
import * as Leo from '@adobe/leonardo-contrast-colors';
const Theme = () => {
const Theme = () => {
let gray = new Leo.BackgroundColor({

@@ -363,19 +378,16 @@ name: 'gray',

});
const adaptiveTheme = new Leo.Theme({
colors: [
gray,
blue,
red
],
backgroundColor: gray,
colors: [gray, blue, red],
backgroundColor: gray,
lightness: 97,
contrast: 1,
contrast: 1
});
return adaptiveTheme;
}
};
export default Theme;
```
Then import your Theme component at the top level of your application, and pass the Theme as a property of your app:

@@ -389,3 +401,3 @@

<React.StrictMode>
<App adaptiveTheme={Theme()}/>
<App adaptiveTheme={Theme()} />
</React.StrictMode>,

@@ -396,3 +408,4 @@ document.getElementById('root')

In your App.js file, import `useTheme` from `css-vars-hook` and provide the following within your App function in order to format Leonardo's output in the structure required for `css-vars-hook`.
In your App.js file, import `useTheme` from `css-vars-hook` and provide the following within your App function in order to format Leonardo's output in the structure required for `css-vars-hook`.
```js

@@ -407,7 +420,7 @@ // App.js

const _createThemeObject = () => {
let themeObj = {}
props.adaptiveTheme.contrastColors.forEach(color => {
if(color.name) {
let themeObj = {};
props.adaptiveTheme.contrastColors.forEach((color) => {
if (color.name) {
let values = color.values;
values.forEach(instance => {
values.forEach((instance) => {
let name = instance.name;

@@ -419,39 +432,34 @@ let val = instance.value;

// must be the background
let name = 'background'
let name = 'background';
let val = color.background;
themeObj[name] = val;
}
})
});
return themeObj;
};
const theme = useState( _createThemeObject() );
const theme = useState(_createThemeObject());
const {setRef, setVariable} = useTheme(theme);
return (
<div
className="App"
ref={setRef}
>
</div>
)
return <div className="App" ref={setRef}></div>;
}
```
```
To make your application adaptive, include a function for updating your theme before your return function:
```js
function _updateColorVariables() {
let themeInstance = _createThemeObject();
function _updateColorVariables() {
let themeInstance = _createThemeObject();
for (const [key, value] of Object.entries( themeInstance )) {
setVariable(key, value);
}
};
// call function to set initial values
_updateColorVariables();
for (const [key, value] of Object.entries(themeInstance)) {
setVariable(key, value);
}
}
// call function to set initial values
_updateColorVariables();
```
Finally, reference this function and set the theme parameters when your users interact with slider components (do the same for Contrast):
```js

@@ -494,21 +502,25 @@ <label htmlFor="lightness">

### Dark mode support in React
Include the following in your App.js file to listen for dark mode. This will pass a different lightness value (of your choice) to Leonardo. It's recommended to restrict the lightness range based on mode in order to avoid inaccessible ranges and to provide a better overall experience
```js
const mq = window.matchMedia('(prefers-color-scheme: dark)');
// Update lightness and slider min/max to be conditional:
const [lightness, setLightness] = useState((mq.matches) ? 8 : 100);
const [sliderMin, setSliderMin] = useState((mq.matches) ? 0 : 80);
const [sliderMax, setSliderMax] = useState((mq.matches) ? 30 : 100);
const [lightness, setLightness] = useState(mq.matches ? 8 : 100);
const [sliderMin, setSliderMin] = useState(mq.matches ? 0 : 80);
const [sliderMax, setSliderMax] = useState(mq.matches ? 30 : 100);
// Listener to update when user device mode changes:
mq.addEventListener('change', function (evt) {
props.adaptiveTheme.lightness = ((mq.matches) ? 11 : 100)
setLightness((mq.matches) ? 11 : 100)
setSliderMin((mq.matches) ? 0 : 80);
setSliderMax((mq.matches) ? 30 : 100);
props.adaptiveTheme.lightness = mq.matches ? 11 : 100;
setLightness(mq.matches ? 11 : 100);
setSliderMin(mq.matches ? 0 : 80);
setSliderMax(mq.matches ? 30 : 100);
});
```
---
## Why are not all contrast ratios available?
You may notice the tool takes an input (target ratio) but most often outputs a contrast ratio slightly higher. This has to do with the available colors in the RGB color space, and the math associated with calculating these ratios.

@@ -528,11 +540,12 @@

Since the WCAG requirement is defined as a *minimum contrast requirement*, it should be fine to generate colors that are a little *more* accessible than the minimum.
Since the WCAG requirement is defined as a _minimum contrast requirement_, it should be fine to generate colors that are a little _more_ accessible than the minimum.
---
## Chroma.js
This project is currently built using [Chroma.js](https://gka.github.io/chroma.js/) with custom extensions to support[CIE CAM02](https://gramaz.io/d3-cam02/). Additional functionality is added in Leonardo to enhance chroma scales so that they properly order colors by lightness and correct the lightness of the scale based on HSLuv.
## Contributing
Contributions are welcomed! Read the [Contributing Guide](../../.github/CONTRIBUTING.md) for more information.

@@ -545,6 +558,13 @@

```sh
yarn dev
pnpm dev
```
or run just tests once with:
```sh
pnpm test
```
## Licensing
This project is licensed under the Apache V2 License. See [LICENSE](LICENSE) for more information.
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