aboutsummaryrefslogtreecommitdiffstats
path: root/packages/excalidraw/colors.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/excalidraw/colors.ts')
-rw-r--r--packages/excalidraw/colors.ts170
1 files changed, 170 insertions, 0 deletions
diff --git a/packages/excalidraw/colors.ts b/packages/excalidraw/colors.ts
new file mode 100644
index 0000000..e4cd67a
--- /dev/null
+++ b/packages/excalidraw/colors.ts
@@ -0,0 +1,170 @@
+import oc from "open-color";
+import type { Merge } from "./utility-types";
+
+// FIXME can't put to utils.ts rn because of circular dependency
+const pick = <R extends Record<string, any>, K extends readonly (keyof R)[]>(
+ source: R,
+ keys: K,
+) => {
+ return keys.reduce((acc, key: K[number]) => {
+ if (key in source) {
+ acc[key] = source[key];
+ }
+ return acc;
+ }, {} as Pick<R, K[number]>) as Pick<R, K[number]>;
+};
+
+export type ColorPickerColor =
+ | Exclude<keyof oc, "indigo" | "lime">
+ | "transparent"
+ | "bronze";
+export type ColorTuple = readonly [string, string, string, string, string];
+export type ColorPalette = Merge<
+ Record<ColorPickerColor, ColorTuple>,
+ { black: "#1e1e1e"; white: "#ffffff"; transparent: "transparent" }
+>;
+
+// used general type instead of specific type (ColorPalette) to support custom colors
+export type ColorPaletteCustom = { [key: string]: ColorTuple | string };
+export type ColorShadesIndexes = [number, number, number, number, number];
+
+export const MAX_CUSTOM_COLORS_USED_IN_CANVAS = 5;
+export const COLORS_PER_ROW = 5;
+
+export const DEFAULT_CHART_COLOR_INDEX = 4;
+
+export const DEFAULT_ELEMENT_STROKE_COLOR_INDEX = 4;
+export const DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX = 1;
+export const ELEMENTS_PALETTE_SHADE_INDEXES = [0, 2, 4, 6, 8] as const;
+export const CANVAS_PALETTE_SHADE_INDEXES = [0, 1, 2, 3, 4] as const;
+
+export const getSpecificColorShades = (
+ color: Exclude<
+ ColorPickerColor,
+ "transparent" | "white" | "black" | "bronze"
+ >,
+ indexArr: Readonly<ColorShadesIndexes>,
+) => {
+ return indexArr.map((index) => oc[color][index]) as any as ColorTuple;
+};
+
+export const COLOR_PALETTE = {
+ transparent: "transparent",
+ black: "#1e1e1e",
+ white: "#ffffff",
+ // open-colors
+ gray: getSpecificColorShades("gray", ELEMENTS_PALETTE_SHADE_INDEXES),
+ red: getSpecificColorShades("red", ELEMENTS_PALETTE_SHADE_INDEXES),
+ pink: getSpecificColorShades("pink", ELEMENTS_PALETTE_SHADE_INDEXES),
+ grape: getSpecificColorShades("grape", ELEMENTS_PALETTE_SHADE_INDEXES),
+ violet: getSpecificColorShades("violet", ELEMENTS_PALETTE_SHADE_INDEXES),
+ blue: getSpecificColorShades("blue", ELEMENTS_PALETTE_SHADE_INDEXES),
+ cyan: getSpecificColorShades("cyan", ELEMENTS_PALETTE_SHADE_INDEXES),
+ teal: getSpecificColorShades("teal", ELEMENTS_PALETTE_SHADE_INDEXES),
+ green: getSpecificColorShades("green", ELEMENTS_PALETTE_SHADE_INDEXES),
+ yellow: getSpecificColorShades("yellow", ELEMENTS_PALETTE_SHADE_INDEXES),
+ orange: getSpecificColorShades("orange", ELEMENTS_PALETTE_SHADE_INDEXES),
+ // radix bronze shades 3,5,7,9,11
+ bronze: ["#f8f1ee", "#eaddd7", "#d2bab0", "#a18072", "#846358"],
+} as ColorPalette;
+
+const COMMON_ELEMENT_SHADES = pick(COLOR_PALETTE, [
+ "cyan",
+ "blue",
+ "violet",
+ "grape",
+ "pink",
+ "green",
+ "teal",
+ "yellow",
+ "orange",
+ "red",
+]);
+
+// -----------------------------------------------------------------------------
+// quick picks defaults
+// -----------------------------------------------------------------------------
+
+// ORDER matters for positioning in quick picker
+export const DEFAULT_ELEMENT_STROKE_PICKS = [
+ COLOR_PALETTE.black,
+ COLOR_PALETTE.red[DEFAULT_ELEMENT_STROKE_COLOR_INDEX],
+ COLOR_PALETTE.green[DEFAULT_ELEMENT_STROKE_COLOR_INDEX],
+ COLOR_PALETTE.blue[DEFAULT_ELEMENT_STROKE_COLOR_INDEX],
+ COLOR_PALETTE.yellow[DEFAULT_ELEMENT_STROKE_COLOR_INDEX],
+] as ColorTuple;
+
+// ORDER matters for positioning in quick picker
+export const DEFAULT_ELEMENT_BACKGROUND_PICKS = [
+ COLOR_PALETTE.transparent,
+ COLOR_PALETTE.red[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX],
+ COLOR_PALETTE.green[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX],
+ COLOR_PALETTE.blue[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX],
+ COLOR_PALETTE.yellow[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX],
+] as ColorTuple;
+
+// ORDER matters for positioning in quick picker
+export const DEFAULT_CANVAS_BACKGROUND_PICKS = [
+ COLOR_PALETTE.white,
+ // radix slate2
+ "#f8f9fa",
+ // radix blue2
+ "#f5faff",
+ // radix yellow2
+ "#fffce8",
+ // radix bronze2
+ "#fdf8f6",
+] as ColorTuple;
+
+// -----------------------------------------------------------------------------
+// palette defaults
+// -----------------------------------------------------------------------------
+
+export const DEFAULT_ELEMENT_STROKE_COLOR_PALETTE = {
+ // 1st row
+ transparent: COLOR_PALETTE.transparent,
+ white: COLOR_PALETTE.white,
+ gray: COLOR_PALETTE.gray,
+ black: COLOR_PALETTE.black,
+ bronze: COLOR_PALETTE.bronze,
+ // rest
+ ...COMMON_ELEMENT_SHADES,
+} as const;
+
+// ORDER matters for positioning in pallete (5x3 grid)s
+export const DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE = {
+ transparent: COLOR_PALETTE.transparent,
+ white: COLOR_PALETTE.white,
+ gray: COLOR_PALETTE.gray,
+ black: COLOR_PALETTE.black,
+ bronze: COLOR_PALETTE.bronze,
+
+ ...COMMON_ELEMENT_SHADES,
+} as const;
+
+// -----------------------------------------------------------------------------
+// helpers
+// -----------------------------------------------------------------------------
+
+// !!!MUST BE WITHOUT GRAY, TRANSPARENT AND BLACK!!!
+export const getAllColorsSpecificShade = (index: 0 | 1 | 2 | 3 | 4) =>
+ [
+ // 2nd row
+ COLOR_PALETTE.cyan[index],
+ COLOR_PALETTE.blue[index],
+ COLOR_PALETTE.violet[index],
+ COLOR_PALETTE.grape[index],
+ COLOR_PALETTE.pink[index],
+
+ // 3rd row
+ COLOR_PALETTE.green[index],
+ COLOR_PALETTE.teal[index],
+ COLOR_PALETTE.yellow[index],
+ COLOR_PALETTE.orange[index],
+ COLOR_PALETTE.red[index],
+ ] as const;
+
+export const rgbToHex = (r: number, g: number, b: number) =>
+ `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
+
+// -----------------------------------------------------------------------------