@@ -1,11 +1,11 @@
-import bezier from "bezier-easing";
-import chroma from "chroma-js";
-import { Color, ColorFamily, ColorFamilyConfig, ColorScale } from "../types";
-import { percentageToNormalized } from "./convert";
-import { curve } from "./curve";
+import bezier from "bezier-easing"
+import chroma from "chroma-js"
+import { Color, ColorFamily, ColorFamilyConfig, ColorScale } from "../types"
+import { percentageToNormalized } from "./convert"
+import { curve } from "./curve"
// Re-export interface in a more standard format
-export type EasingFunction = bezier.EasingFunction;
+export type EasingFunction = bezier.EasingFunction
/**
* Generates a color, outputs it in multiple formats, and returns a variety of useful metadata.
@@ -20,60 +20,60 @@ export type EasingFunction = bezier.EasingFunction;
* @returns {Color} The generated color, with its calculated contrast against black and white, as well as its LCH values, RGBA array, hexadecimal representation, and a flag indicating if it is light or dark.
*/
function generateColor(
- hueEasing: EasingFunction,
- saturationEasing: EasingFunction,
- lightnessEasing: EasingFunction,
- family: ColorFamilyConfig,
- step: number,
- steps: number
+ hueEasing: EasingFunction,
+ saturationEasing: EasingFunction,
+ lightnessEasing: EasingFunction,
+ family: ColorFamilyConfig,
+ step: number,
+ steps: number
) {
- const { hue, saturation, lightness } = family.color;
-
- const stepHue = hueEasing(step / steps) * (hue.end - hue.start) + hue.start;
- const stepSaturation =
- saturationEasing(step / steps) * (saturation.end - saturation.start) +
- saturation.start;
- const stepLightness =
- lightnessEasing(step / steps) * (lightness.end - lightness.start) +
- lightness.start;
-
- const color = chroma.hsl(
- stepHue,
- percentageToNormalized(stepSaturation),
- percentageToNormalized(stepLightness)
- );
-
- const contrast = {
- black: {
- value: chroma.contrast(color, "black"),
- aaPass: chroma.contrast(color, "black") >= 4.5,
- aaaPass: chroma.contrast(color, "black") >= 7,
- },
- white: {
- value: chroma.contrast(color, "white"),
- aaPass: chroma.contrast(color, "white") >= 4.5,
- aaaPass: chroma.contrast(color, "white") >= 7,
- },
- };
-
- const lch = color.lch();
- const rgba = color.rgba();
- const hex = color.hex();
-
- // 55 is a magic number. It's the lightness value at which we consider a color to be "light".
- // It was picked by eye with some testing. We might want to use a more scientific approach in the future.
- const isLight = lch[0] > 55;
-
- const result: Color = {
- step,
- lch,
- hex,
- rgba,
- contrast,
- isLight,
- };
-
- return result;
+ const { hue, saturation, lightness } = family.color
+
+ const stepHue = hueEasing(step / steps) * (hue.end - hue.start) + hue.start
+ const stepSaturation =
+ saturationEasing(step / steps) * (saturation.end - saturation.start) +
+ saturation.start
+ const stepLightness =
+ lightnessEasing(step / steps) * (lightness.end - lightness.start) +
+ lightness.start
+
+ const color = chroma.hsl(
+ stepHue,
+ percentageToNormalized(stepSaturation),
+ percentageToNormalized(stepLightness)
+ )
+
+ const contrast = {
+ black: {
+ value: chroma.contrast(color, "black"),
+ aaPass: chroma.contrast(color, "black") >= 4.5,
+ aaaPass: chroma.contrast(color, "black") >= 7,
+ },
+ white: {
+ value: chroma.contrast(color, "white"),
+ aaPass: chroma.contrast(color, "white") >= 4.5,
+ aaaPass: chroma.contrast(color, "white") >= 7,
+ },
+ }
+
+ const lch = color.lch()
+ const rgba = color.rgba()
+ const hex = color.hex()
+
+ // 55 is a magic number. It's the lightness value at which we consider a color to be "light".
+ // It was picked by eye with some testing. We might want to use a more scientific approach in the future.
+ const isLight = lch[0] > 55
+
+ const result: Color = {
+ step,
+ lch,
+ hex,
+ rgba,
+ contrast,
+ isLight,
+ }
+
+ return result
}
/**
@@ -110,50 +110,50 @@ function generateColor(
*/
export function generateColorScale(
- config: ColorFamilyConfig,
- inverted: Boolean = false
+ config: ColorFamilyConfig,
+ inverted: Boolean = false
) {
- const { hue, saturation, lightness } = config.color;
-
- // 101 steps means we get values from 0-100
- const NUM_STEPS = 101;
-
- const hueEasing = curve(hue.curve, inverted);
- const saturationEasing = curve(saturation.curve, inverted);
- const lightnessEasing = curve(lightness.curve, inverted);
-
- let scale: ColorScale = {
- colors: [],
- values: [],
- };
-
- for (let i = 0; i < NUM_STEPS; i++) {
- const color = generateColor(
- hueEasing,
- saturationEasing,
- lightnessEasing,
- config,
- i,
- NUM_STEPS
- );
-
- scale.colors.push(color);
- scale.values.push(color.hex);
- }
-
- return scale;
+ const { hue, saturation, lightness } = config.color
+
+ // 101 steps means we get values from 0-100
+ const NUM_STEPS = 101
+
+ const hueEasing = curve(hue.curve, inverted)
+ const saturationEasing = curve(saturation.curve, inverted)
+ const lightnessEasing = curve(lightness.curve, inverted)
+
+ let scale: ColorScale = {
+ colors: [],
+ values: [],
+ }
+
+ for (let i = 0; i < NUM_STEPS; i++) {
+ const color = generateColor(
+ hueEasing,
+ saturationEasing,
+ lightnessEasing,
+ config,
+ i,
+ NUM_STEPS
+ )
+
+ scale.colors.push(color)
+ scale.values.push(color.hex)
+ }
+
+ return scale
}
/** Generates a color family with a scale and an inverted scale. */
export function generateColorFamily(config: ColorFamilyConfig) {
- const scale = generateColorScale(config, false);
- const invertedScale = generateColorScale(config, true);
+ const scale = generateColorScale(config, false)
+ const invertedScale = generateColorScale(config, true)
- const family: ColorFamily = {
- name: config.name,
- scale,
- invertedScale,
- };
+ const family: ColorFamily = {
+ name: config.name,
+ scale,
+ invertedScale,
+ }
- return family;
+ return family
}
@@ -1,5 +1,5 @@
-import { generateColorFamily } from "../lib/generate";
-import { curve } from "./curves";
+import { generateColorFamily } from "../lib/generate"
+import { curve } from "./curves"
// These are the source colors for the color scales in the system.
// These should never directly be used directly in components or themes as they generate thousands of lines of code.
@@ -10,436 +10,436 @@ import { curve } from "./curves";
// Light Gray ======================================== //
export const lightgray = generateColorFamily({
- name: "lightgray",
- color: {
- hue: {
- start: 210,
- end: 210,
- curve: curve.linear,
- },
- saturation: {
- start: 10,
- end: 15,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 50,
- curve: curve.linear,
- },
- },
-});
+ name: "lightgray",
+ color: {
+ hue: {
+ start: 210,
+ end: 210,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 10,
+ end: 15,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 50,
+ curve: curve.linear,
+ },
+ },
+})
// Light Dark ======================================== //
export const darkgray = generateColorFamily({
- name: "darkgray",
- color: {
- hue: {
- start: 210,
- end: 210,
- curve: curve.linear,
- },
- saturation: {
- start: 15,
- end: 20,
- curve: curve.saturation,
- },
- lightness: {
- start: 55,
- end: 8,
- curve: curve.linear,
- },
- },
-});
+ name: "darkgray",
+ color: {
+ hue: {
+ start: 210,
+ end: 210,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 15,
+ end: 20,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 55,
+ end: 8,
+ curve: curve.linear,
+ },
+ },
+})
// Red ======================================== //
export const red = generateColorFamily({
- name: "red",
- color: {
- hue: {
- start: 0,
- end: 0,
- curve: curve.linear,
- },
- saturation: {
- start: 95,
- end: 75,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 25,
- curve: curve.lightness,
- },
- },
-});
+ name: "red",
+ color: {
+ hue: {
+ start: 0,
+ end: 0,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 95,
+ end: 75,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 25,
+ curve: curve.lightness,
+ },
+ },
+})
// Sunset ======================================== //
export const sunset = generateColorFamily({
- name: "sunset",
- color: {
- hue: {
- start: 15,
- end: 15,
- curve: curve.linear,
- },
- saturation: {
- start: 100,
- end: 90,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 25,
- curve: curve.lightness,
- },
- },
-});
+ name: "sunset",
+ color: {
+ hue: {
+ start: 15,
+ end: 15,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 100,
+ end: 90,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 25,
+ curve: curve.lightness,
+ },
+ },
+})
// Orange ======================================== //
export const orange = generateColorFamily({
- name: "orange",
- color: {
- hue: {
- start: 25,
- end: 25,
- curve: curve.linear,
- },
- saturation: {
- start: 100,
- end: 95,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 20,
- curve: curve.lightness,
- },
- },
-});
+ name: "orange",
+ color: {
+ hue: {
+ start: 25,
+ end: 25,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 100,
+ end: 95,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 20,
+ curve: curve.lightness,
+ },
+ },
+})
// Amber ======================================== //
export const amber = generateColorFamily({
- name: "amber",
- color: {
- hue: {
- start: 38,
- end: 38,
- curve: curve.linear,
- },
- saturation: {
- start: 100,
- end: 100,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 18,
- curve: curve.lightness,
- },
- },
-});
+ name: "amber",
+ color: {
+ hue: {
+ start: 38,
+ end: 38,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 100,
+ end: 100,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 18,
+ curve: curve.lightness,
+ },
+ },
+})
// Yellow ======================================== //
export const yellow = generateColorFamily({
- name: "yellow",
- color: {
- hue: {
- start: 48,
- end: 48,
- curve: curve.linear,
- },
- saturation: {
- start: 90,
- end: 100,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 15,
- curve: curve.lightness,
- },
- },
-});
+ name: "yellow",
+ color: {
+ hue: {
+ start: 48,
+ end: 48,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 90,
+ end: 100,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 15,
+ curve: curve.lightness,
+ },
+ },
+})
// Lemon ======================================== //
export const lemon = generateColorFamily({
- name: "lemon",
- color: {
- hue: {
- start: 55,
- end: 55,
- curve: curve.linear,
- },
- saturation: {
- start: 85,
- end: 95,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 15,
- curve: curve.lightness,
- },
- },
-});
+ name: "lemon",
+ color: {
+ hue: {
+ start: 55,
+ end: 55,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 85,
+ end: 95,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 15,
+ curve: curve.lightness,
+ },
+ },
+})
// Citron ======================================== //
export const citron = generateColorFamily({
- name: "citron",
- color: {
- hue: {
- start: 70,
- end: 70,
- curve: curve.linear,
- },
- saturation: {
- start: 85,
- end: 90,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 15,
- curve: curve.lightness,
- },
- },
-});
+ name: "citron",
+ color: {
+ hue: {
+ start: 70,
+ end: 70,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 85,
+ end: 90,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 15,
+ curve: curve.lightness,
+ },
+ },
+})
// Lime ======================================== //
export const lime = generateColorFamily({
- name: "lime",
- color: {
- hue: {
- start: 85,
- end: 85,
- curve: curve.linear,
- },
- saturation: {
- start: 85,
- end: 80,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 18,
- curve: curve.lightness,
- },
- },
-});
+ name: "lime",
+ color: {
+ hue: {
+ start: 85,
+ end: 85,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 85,
+ end: 80,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 18,
+ curve: curve.lightness,
+ },
+ },
+})
// Green ======================================== //
export const green = generateColorFamily({
- name: "green",
- color: {
- hue: {
- start: 108,
- end: 108,
- curve: curve.linear,
- },
- saturation: {
- start: 60,
- end: 70,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 18,
- curve: curve.lightness,
- },
- },
-});
+ name: "green",
+ color: {
+ hue: {
+ start: 108,
+ end: 108,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 60,
+ end: 70,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 18,
+ curve: curve.lightness,
+ },
+ },
+})
// Mint ======================================== //
export const mint = generateColorFamily({
- name: "mint",
- color: {
- hue: {
- start: 142,
- end: 142,
- curve: curve.linear,
- },
- saturation: {
- start: 60,
- end: 75,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 20,
- curve: curve.lightness,
- },
- },
-});
+ name: "mint",
+ color: {
+ hue: {
+ start: 142,
+ end: 142,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 60,
+ end: 75,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 20,
+ curve: curve.lightness,
+ },
+ },
+})
// Cyan ======================================== //
export const cyan = generateColorFamily({
- name: "cyan",
- color: {
- hue: {
- start: 179,
- end: 179,
- curve: curve.linear,
- },
- saturation: {
- start: 70,
- end: 80,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 20,
- curve: curve.lightness,
- },
- },
-});
+ name: "cyan",
+ color: {
+ hue: {
+ start: 179,
+ end: 179,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 70,
+ end: 80,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 20,
+ curve: curve.lightness,
+ },
+ },
+})
// Sky ======================================== //
export const sky = generateColorFamily({
- name: "sky",
- color: {
- hue: {
- start: 195,
- end: 205,
- curve: curve.linear,
- },
- saturation: {
- start: 85,
- end: 90,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 15,
- curve: curve.lightness,
- },
- },
-});
+ name: "sky",
+ color: {
+ hue: {
+ start: 195,
+ end: 205,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 85,
+ end: 90,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 15,
+ curve: curve.lightness,
+ },
+ },
+})
// Blue ======================================== //
export const blue = generateColorFamily({
- name: "blue",
- color: {
- hue: {
- start: 218,
- end: 218,
- curve: curve.linear,
- },
- saturation: {
- start: 85,
- end: 70,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 15,
- curve: curve.lightness,
- },
- },
-});
+ name: "blue",
+ color: {
+ hue: {
+ start: 218,
+ end: 218,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 85,
+ end: 70,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 15,
+ curve: curve.lightness,
+ },
+ },
+})
// Indigo ======================================== //
export const indigo = generateColorFamily({
- name: "indigo",
- color: {
- hue: {
- start: 245,
- end: 245,
- curve: curve.linear,
- },
- saturation: {
- start: 60,
- end: 50,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 22,
- curve: curve.lightness,
- },
- },
-});
+ name: "indigo",
+ color: {
+ hue: {
+ start: 245,
+ end: 245,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 60,
+ end: 50,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 22,
+ curve: curve.lightness,
+ },
+ },
+})
// Purple ======================================== //
export const purple = generateColorFamily({
- name: "purple",
- color: {
- hue: {
- start: 260,
- end: 270,
- curve: curve.linear,
- },
- saturation: {
- start: 65,
- end: 55,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 20,
- curve: curve.lightness,
- },
- },
-});
+ name: "purple",
+ color: {
+ hue: {
+ start: 260,
+ end: 270,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 65,
+ end: 55,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 20,
+ curve: curve.lightness,
+ },
+ },
+})
// Pink ======================================== //
export const pink = generateColorFamily({
- name: "pink",
- color: {
- hue: {
- start: 320,
- end: 330,
- curve: curve.linear,
- },
- saturation: {
- start: 70,
- end: 65,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 32,
- curve: curve.lightness,
- },
- },
-});
+ name: "pink",
+ color: {
+ hue: {
+ start: 320,
+ end: 330,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 70,
+ end: 65,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 32,
+ curve: curve.lightness,
+ },
+ },
+})
// Rose ======================================== //
export const rose = generateColorFamily({
- name: "rose",
- color: {
- hue: {
- start: 345,
- end: 345,
- curve: curve.linear,
- },
- saturation: {
- start: 90,
- end: 70,
- curve: curve.saturation,
- },
- lightness: {
- start: 97,
- end: 32,
- curve: curve.lightness,
- },
- },
-});
+ name: "rose",
+ color: {
+ hue: {
+ start: 345,
+ end: 345,
+ curve: curve.linear,
+ },
+ saturation: {
+ start: 90,
+ end: 70,
+ curve: curve.saturation,
+ },
+ lightness: {
+ start: 97,
+ end: 32,
+ curve: curve.lightness,
+ },
+ },
+})