refactor: update SCSS syntax & remove open-color dep (#10633)

This commit is contained in:
David Luzar
2026-01-10 18:15:14 +01:00
committed by GitHub
parent cc6c29c0b9
commit b9a255407f
78 changed files with 526 additions and 410 deletions
@@ -1,46 +0,0 @@
import { THEME } from "@excalidraw/common";
import oc from "open-color";
import React from "react";
import type { Theme } from "@excalidraw/element/types";
// https://github.com/tholman/github-corners
export const GitHubCorner = React.memo(
({ theme, dir }: { theme: Theme; dir: string }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="40"
height="40"
viewBox="0 0 250 250"
className="rtl-mirror"
style={{
marginTop: "calc(var(--space-factor) * -1)",
[dir === "rtl" ? "marginLeft" : "marginRight"]:
"calc(var(--space-factor) * -1)",
}}
>
<a
href="https://github.com/excalidraw/excalidraw"
target="_blank"
rel="noopener noreferrer"
aria-label="GitHub repository"
>
<path
d="M0 0l115 115h15l12 27 108 108V0z"
fill={theme === THEME.LIGHT ? oc.gray[6] : oc.gray[7]}
/>
<path
className="octo-arm"
d="M128 109c-15-9-9-19-9-19 3-7 2-11 2-11-1-7 3-2 3-2 4 5 2 11 2 11-3 10 5 15 9 16"
style={{ transformOrigin: "130px 106px" }}
fill={theme === THEME.LIGHT ? oc.white : "var(--default-bg-color)"}
/>
<path
className="octo-body"
d="M115 115s4 2 5 0l14-14c3-2 6-3 8-3-8-11-15-24 2-41 5-5 10-7 16-7 1-2 3-7 12-11 0 0 5 3 7 16 4 2 8 5 12 9s7 8 9 12c14 3 17 7 17 7-4 8-9 11-11 11 0 6-2 11-7 16-16 16-30 10-41 2 0 3-1 7-5 11l-12 11c-1 1 1 5 1 5z"
fill={theme === THEME.LIGHT ? oc.white : "var(--default-bg-color)"}
/>
</a>
</svg>
),
);
@@ -1,5 +1,97 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`COLOR_PALETTE > color palette doesn't regress 1`] = `
{
"black": "#1e1e1e",
"blue": [
"#e7f5ff",
"#a5d8ff",
"#4dabf7",
"#228be6",
"#1971c2",
],
"bronze": [
"#f8f1ee",
"#eaddd7",
"#d2bab0",
"#a18072",
"#846358",
],
"cyan": [
"#e3fafc",
"#99e9f2",
"#3bc9db",
"#15aabf",
"#0c8599",
],
"grape": [
"#f8f0fc",
"#eebefa",
"#da77f2",
"#be4bdb",
"#9c36b5",
],
"gray": [
"#f8f9fa",
"#e9ecef",
"#ced4da",
"#868e96",
"#343a40",
],
"green": [
"#ebfbee",
"#b2f2bb",
"#69db7c",
"#40c057",
"#2f9e44",
],
"orange": [
"#fff4e6",
"#ffd8a8",
"#ffa94d",
"#fd7e14",
"#e8590c",
],
"pink": [
"#fff0f6",
"#fcc2d7",
"#f783ac",
"#e64980",
"#c2255c",
],
"red": [
"#fff5f5",
"#ffc9c9",
"#ff8787",
"#fa5252",
"#e03131",
],
"teal": [
"#e6fcf5",
"#96f2d7",
"#38d9a9",
"#12b886",
"#099268",
],
"transparent": "transparent",
"violet": [
"#f3f0ff",
"#d0bfff",
"#9775fa",
"#7950f2",
"#6741d9",
],
"white": "#ffffff",
"yellow": [
"#fff9db",
"#ffec99",
"#ffd43b",
"#fab005",
"#f08c00",
],
}
`;
exports[`applyDarkModeFilter > COLOR_PALETTE regression tests > matches snapshot for all palette colors 1`] = `
{
"black": "#d3d3d3",
+6
View File
@@ -4,6 +4,12 @@ import {
rgbToHex,
} from "@excalidraw/common";
describe("COLOR_PALETTE", () => {
it("color palette doesn't regress", () => {
expect(COLOR_PALETTE).toMatchSnapshot();
});
});
describe("applyDarkModeFilter", () => {
describe("basic transformations", () => {
it("transforms black to near-white", () => {
+102 -48
View File
@@ -1,4 +1,3 @@
import oc from "open-color";
import tinycolor from "tinycolor2";
import { clamp } from "@excalidraw/math";
@@ -6,18 +5,14 @@ import { degreesToRadians } from "@excalidraw/math";
import type { Degrees } from "@excalidraw/math";
import type { Merge } from "./utility-types";
export { tinycolor };
// ---------------------------------------------------------------------------
// Dark mode color transformation
// ---------------------------------------------------------------------------
// Browser-only cache to avoid memory leaks on server
const DARK_MODE_COLORS_CACHE: Map<string, string> | null =
typeof window !== "undefined" ? new Map() : null;
// ---------------------------------------------------------------------------
// Dark mode color transformation
// ---------------------------------------------------------------------------
function cssHueRotate(
red: number,
green: number,
@@ -115,8 +110,8 @@ export const applyDarkModeFilter = (color: string): string => {
};
// ---------------------------------------------------------------------------
export const COLOR_OUTLINE_CONTRAST_THRESHOLD = 240;
// Color palette
// ---------------------------------------------------------------------------
// FIXME can't put to utils.ts rn because of circular dependency
const pick = <R extends Record<string, any>, K extends readonly (keyof R)[]>(
@@ -131,15 +126,7 @@ const pick = <R extends Record<string, any>, K extends readonly (keyof R)[]>(
}, {} 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 };
@@ -152,38 +139,30 @@ 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
// open-color from https://github.com/yeun/open-color/blob/master/open-color.js
// corresponds to indexes [0,2,4,6,8] (weights: 50, 200, 400, 600, 800)
gray: ["#f8f9fa", "#e9ecef", "#ced4da", "#868e96", "#343a40"],
red: ["#fff5f5", "#ffc9c9", "#ff8787", "#fa5252", "#e03131"],
pink: ["#fff0f6", "#fcc2d7", "#f783ac", "#e64980", "#c2255c"],
grape: ["#f8f0fc", "#eebefa", "#da77f2", "#be4bdb", "#9c36b5"],
violet: ["#f3f0ff", "#d0bfff", "#9775fa", "#7950f2", "#6741d9"],
blue: ["#e7f5ff", "#a5d8ff", "#4dabf7", "#228be6", "#1971c2"],
cyan: ["#e3fafc", "#99e9f2", "#3bc9db", "#15aabf", "#0c8599"],
teal: ["#e6fcf5", "#96f2d7", "#38d9a9", "#12b886", "#099268"],
green: ["#ebfbee", "#b2f2bb", "#69db7c", "#40c057", "#2f9e44"],
yellow: ["#fff9db", "#ffec99", "#ffd43b", "#fab005", "#f08c00"],
orange: ["#fff4e6", "#ffd8a8", "#ffa94d", "#fd7e14", "#e8590c"],
// radix bronze shades [3,5,7,9,11]
bronze: ["#f8f1ee", "#eaddd7", "#d2bab0", "#a18072", "#846358"],
} as ColorPalette;
} as const;
export type ColorPalette = typeof COLOR_PALETTE;
export type ColorPickerColor = keyof typeof COLOR_PALETTE;
const COMMON_ELEMENT_SHADES = pick(COLOR_PALETTE, [
"cyan",
@@ -198,7 +177,6 @@ const COMMON_ELEMENT_SHADES = pick(COLOR_PALETTE, [
"red",
]);
// -----------------------------------------------------------------------------
// quick picks defaults
// -----------------------------------------------------------------------------
@@ -233,7 +211,6 @@ export const DEFAULT_CANVAS_BACKGROUND_PICKS = [
"#fdf8f6",
] as ColorTuple;
// -----------------------------------------------------------------------------
// palette defaults
// -----------------------------------------------------------------------------
@@ -259,8 +236,7 @@ export const DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE = {
...COMMON_ELEMENT_SHADES,
} as const;
// -----------------------------------------------------------------------------
// helpers
// color palette helpers
// -----------------------------------------------------------------------------
// !!!MUST BE WITHOUT GRAY, TRANSPARENT AND BLACK!!!
@@ -281,6 +257,10 @@ export const getAllColorsSpecificShade = (index: 0 | 1 | 2 | 3 | 4) =>
COLOR_PALETTE.red[index],
] as const;
// -----------------------------------------------------------------------------
// other helpers
// -----------------------------------------------------------------------------
export const rgbToHex = (r: number, g: number, b: number, a?: number) => {
// (1 << 24) adds 0x1000000 to ensure the hex string is always 7 chars,
// then slice(1) removes the leading "1" to get exactly 6 hex digits
@@ -299,4 +279,78 @@ export const rgbToHex = (r: number, g: number, b: number, a?: number) => {
return hex6;
};
/**
* @returns #RRGGBB or #RRGGBBAA based on color containing non-opaque alpha,
* null if not valid color
*/
export const colorToHex = (color: string): string | null => {
const tc = tinycolor(color);
if (!tc.isValid()) {
return null;
}
const { r, g, b, a } = tc.toRgb();
return rgbToHex(r, g, b, a);
};
export const isTransparent = (color: string) => {
return tinycolor(color).getAlpha() === 0;
};
// -----------------------------------------------------------------------------
// color contract helpers
// -----------------------------------------------------------------------------
export const COLOR_OUTLINE_CONTRAST_THRESHOLD = 240;
const calculateContrast = (r: number, g: number, b: number): number => {
const yiq = (r * 299 + g * 587 + b * 114) / 1000;
return yiq;
};
// YIQ algo, inspiration from https://stackoverflow.com/a/11868398
export const isColorDark = (color: string, threshold = 160): boolean => {
// no color ("") -> assume it default to black
if (!color) {
return true;
}
if (isTransparent(color)) {
return false;
}
const tc = tinycolor(color);
if (!tc.isValid()) {
// invalid color -> assume it defaults to black
return true;
}
const { r, g, b } = tc.toRgb();
return calculateContrast(r, g, b) < threshold;
};
// -----------------------------------------------------------------------------
// normalization
// -----------------------------------------------------------------------------
/**
* tries to keep the input color as-is if it's valid, making minimal adjustments
* (trimming whitespace or adding `#` to hex colors)
*/
export const normalizeInputColor = (color: string): string | null => {
color = color.trim();
if (isTransparent(color)) {
return color;
}
const tc = tinycolor(color);
if (tc.isValid()) {
// testing for `#` first fixes a bug on Electron (more specfically, an
// Obsidian popout window), where a hex color without `#` is considered valid
if (tc.getFormat() === "hex" && !color.startsWith("#")) {
return `#${color}`;
}
return color;
}
return null;
};
-5
View File
@@ -10,7 +10,6 @@ import type {
Zoom,
} from "@excalidraw/excalidraw/types";
import { tinycolor } from "./colors";
import {
DEFAULT_VERSION,
ENV,
@@ -548,10 +547,6 @@ export const mapFind = <T, K>(
return undefined;
};
export const isTransparent = (color: string) => {
return tinycolor(color).getAlpha() === 0;
};
export type ResolvablePromise<T> = Promise<T> & {
resolve: [T] extends [undefined]
? (value?: MaybePromise<Awaited<T>>) => void
+1 -1
View File
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.Avatar {
+1 -1
View File
@@ -1,4 +1,4 @@
@import "../css/theme";
@use "../css/theme" as *;
.excalidraw {
.excalidraw-button {
@@ -1,4 +1,4 @@
@import "../css/theme";
@use "../css/theme" as *;
.excalidraw {
button.standalone {
+3 -3
View File
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module.scss" as *;
.excalidraw {
.Card {
@@ -19,7 +19,7 @@
padding: 1.4rem;
border-radius: 50%;
background: var(--card-color);
color: $oc-white;
color: #fff;
svg {
width: 2.8rem;
@@ -46,7 +46,7 @@
background-color: var(--card-color-darkest);
}
.ToolIcon__label {
color: $oc-white;
color: #fff;
}
.Spinner {
+23 -13
View File
@@ -1,25 +1,35 @@
import OpenColor from "open-color";
import "./Card.scss";
// for open-color see https://github.com/yeun/open-color/blob/master/open-color.scss
const COLOR_MAP = {
primary: {
base: "var(--color-primary)",
darker: "var(--color-primary-darker)",
darkest: "var(--color-primary-darkest)",
},
lime: {
base: "#74b816", // open-color lime[7]
darker: "#66a80f", // open-color lime[8]
darkest: "#5c940d", // open-color lime[9]
},
pink: {
base: "#d6336c", // open-color pink[7]
darker: "#c2255c", // open-color pink[8]
darkest: "#a61e4d", // open-color pink[9]
},
};
export const Card: React.FC<{
color: keyof OpenColor | "primary";
color: "primary" | "lime" | "pink";
children?: React.ReactNode;
}> = ({ children, color }) => {
return (
<div
className="Card"
style={{
["--card-color" as any]:
color === "primary" ? "var(--color-primary)" : OpenColor[color][7],
["--card-color-darker" as any]:
color === "primary"
? "var(--color-primary-darker)"
: OpenColor[color][8],
["--card-color-darkest" as any]:
color === "primary"
? "var(--color-primary-darkest)"
: OpenColor[color][9],
["--card-color" as any]: COLOR_MAP[color].base,
["--card-color-darker" as any]: COLOR_MAP[color].darker,
["--card-color-darkest" as any]: COLOR_MAP[color].darkest,
}}
>
{children}
@@ -1,4 +1,5 @@
@import "../css/variables.module.scss";
@use "sass:color";
@use "../css/variables.module" as *;
.excalidraw {
.Checkbox {
@@ -12,7 +13,7 @@
-webkit-tap-highlight-color: transparent;
&:hover:not(.is-checked) .Checkbox-box:not(:focus) {
box-shadow: 0 0 0 2px #{$oc-blue-4};
box-shadow: 0 0 0 2px #{$color-blue-4};
}
&:hover:not(.is-checked) .Checkbox-box:not(:focus) {
@@ -24,25 +25,25 @@
&:active {
.Checkbox-box {
box-shadow: 0 0 2px 1px inset #{$oc-blue-7} !important;
box-shadow: 0 0 2px 1px inset #{$color-blue-7} !important;
}
}
&:hover {
.Checkbox-box {
background-color: fade-out($oc-blue-1, 0.8);
background-color: color.adjust($color-blue-1, $alpha: -0.8);
}
}
&.is-checked {
.Checkbox-box {
background-color: #{$oc-blue-1};
background-color: #{$color-blue-1};
svg {
display: block;
}
}
&:hover .Checkbox-box {
background-color: #{$oc-blue-2};
background-color: #{$color-blue-2};
}
}
@@ -58,16 +59,16 @@
align-items: center;
justify-content: center;
box-shadow: 0 0 0 2px #{$oc-blue-7};
box-shadow: 0 0 0 2px #{$color-blue-7};
background-color: transparent;
border-radius: 4px;
color: #{$oc-blue-7};
color: #{$color-blue-7};
border: 0;
&:focus {
box-shadow: 0 0 0 3px #{$oc-blue-7};
box-shadow: 0 0 0 3px #{$color-blue-7};
}
svg {
@@ -1,9 +1,7 @@
import clsx from "clsx";
import { useCallback, useEffect, useRef, useState } from "react";
import { isTransparent, KEYS } from "@excalidraw/common";
import tinycolor from "tinycolor2";
import { KEYS, normalizeInputColor } from "@excalidraw/common";
import { getShortcutKey } from "../..//shortcut";
import { useAtom } from "../../editor-jotai";
@@ -16,29 +14,6 @@ import { activeColorPickerSectionAtom } from "./colorPickerUtils";
import type { ColorPickerType } from "./colorPickerUtils";
/**
* tries to keep the input color as-is if it's valid, making minimal adjustments
* (trimming whitespace or adding `#` to hex colors)
*/
export const normalizeInputColor = (color: string): string | null => {
color = color.trim();
if (isTransparent(color)) {
return color;
}
const tc = tinycolor(color);
if (tc.isValid()) {
// testing for `#` first fixes a bug on Electron (more specfically, an
// Obsidian popout window), where a hex color without `#` is considered valid
if (tc.getFormat() === "hex" && !color.startsWith("#")) {
return `#${color}`;
}
return color;
}
return null;
};
export const ColorInput = ({
color,
onChange,
@@ -1,4 +1,5 @@
@import "../../css/variables.module.scss";
@use "sass:color";
@use "../../css/variables.module" as *;
.excalidraw {
.focus-visible-none {
@@ -185,8 +186,8 @@
.color-picker {
background: var(--popup-bg-color);
border: 0 solid transparentize($oc-white, 0.75);
box-shadow: transparentize($oc-black, 0.75) 0 1px 4px;
border: 0 solid color.adjust(#fff, $alpha: -0.75);
box-shadow: color.adjust(#000, $alpha: -0.75) 0 1px 4px;
border-radius: 4px;
position: absolute;
@@ -243,7 +244,7 @@
}
.color-picker-triangle-shadow {
border-color: transparent transparent transparentize($oc-black, 0.9);
border-color: transparent transparent color.adjust(#000, $alpha: -0.9);
:root[dir="ltr"] & {
left: -14px;
@@ -280,7 +281,7 @@
padding: 0.25rem;
&-title {
color: $oc-gray-6;
color: $color-gray-6;
font-size: 12px;
padding: 0 0.25rem;
}
@@ -319,7 +320,7 @@
.color-picker-transparent {
border-radius: 4px;
box-shadow: transparentize($oc-black, 0.9) 0 0 0 1px inset;
box-shadow: color.adjust(#000, $alpha: -0.9) 0 0 0 1px inset;
position: absolute;
top: 0;
right: 0;
@@ -473,7 +474,7 @@
}
.color-picker-type-elementBackground .color-picker-keybinding {
color: $oc-white;
color: #fff;
}
.color-picker-swatch[aria-label="transparent"] .color-picker-keybinding {
@@ -486,10 +487,10 @@
&.theme--dark {
.color-picker-type-elementBackground .color-picker-keybinding {
color: $oc-black;
color: #000;
}
.color-picker-swatch[aria-label="transparent"] .color-picker-keybinding {
color: $oc-black;
color: #000;
}
}
}
@@ -5,6 +5,7 @@ import { useRef, useEffect } from "react";
import {
COLOR_OUTLINE_CONTRAST_THRESHOLD,
COLOR_PALETTE,
isColorDark,
isWritableElement,
} from "@excalidraw/common";
@@ -29,7 +30,7 @@ import { ColorInput } from "./ColorInput";
import { Picker } from "./Picker";
import PickerHeading from "./PickerHeading";
import { TopPicks } from "./TopPicks";
import { activeColorPickerSectionAtom, isColorDark } from "./colorPickerUtils";
import { activeColorPickerSectionAtom } from "./colorPickerUtils";
import "./ColorPicker.scss";
@@ -1,6 +1,5 @@
import React from "react";
import { isColorDark } from "./colorPickerUtils";
import { isColorDark } from "@excalidraw/common";
interface HotkeyLabelProps {
color: string;
@@ -5,10 +5,9 @@ import {
DEFAULT_CANVAS_BACKGROUND_PICKS,
DEFAULT_ELEMENT_BACKGROUND_PICKS,
DEFAULT_ELEMENT_STROKE_PICKS,
isColorDark,
} from "@excalidraw/common";
import { isColorDark } from "./colorPickerUtils";
import type { ColorPickerType } from "./colorPickerUtils";
interface TopPicksProps {
@@ -1,8 +1,4 @@
import {
isTransparent,
MAX_CUSTOM_COLORS_USED_IN_CANVAS,
tinycolor,
} from "@excalidraw/common";
import { MAX_CUSTOM_COLORS_USED_IN_CANVAS } from "@excalidraw/common";
import type { ExcalidrawElement } from "@excalidraw/element/types";
@@ -100,32 +96,6 @@ export type ActiveColorPickerSectionAtomType =
export const activeColorPickerSectionAtom =
atom<ActiveColorPickerSectionAtomType>(null);
const calculateContrast = (r: number, g: number, b: number): number => {
const yiq = (r * 299 + g * 587 + b * 114) / 1000;
return yiq;
};
// YIQ algo, inspiration from https://stackoverflow.com/a/11868398
export const isColorDark = (color: string, threshold = 160): boolean => {
// no color ("") -> assume it default to black
if (!color) {
return true;
}
if (isTransparent(color)) {
return false;
}
const tc = tinycolor(color);
if (!tc.isValid()) {
// invalid color -> assume it defaults to black
return true;
}
const { r, g, b } = tc.toRgb();
return calculateContrast(r, g, b) < threshold;
};
export type ColorPickerType =
| "canvasBackground"
| "elementBackground"
@@ -1,4 +1,4 @@
@import "../../css/variables.module.scss";
@use "../../css/variables.module" as *;
$verticalBreakpoint: 861px;
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.confirm-dialog {
@@ -1,4 +1,5 @@
@import "../css/variables.module.scss";
@use "sass:color";
@use "../css/variables.module" as *;
.excalidraw {
.context-menu-popover {
@@ -8,7 +9,7 @@
.context-menu {
position: relative;
border-radius: 4px;
box-shadow: 0 3px 10px transparentize($oc-black, 0.8);
box-shadow: 0 3px 10px color.adjust(#000, $alpha: -0.8);
padding: 0;
list-style: none;
user-select: none;
@@ -49,7 +50,7 @@
&.dangerous {
.context-menu-item__label {
color: $oc-red-7;
color: $color-red-7;
}
}
@@ -73,7 +74,7 @@
.context-menu-item__label {
color: var(--popup-bg-color);
}
background-color: $oc-red-6;
background-color: $color-red-6;
}
}
@@ -97,6 +98,6 @@
.context-menu-item-separator {
border: none;
border-top: 1px solid $oc-gray-5;
border-top: 1px solid $color-gray-5;
}
}
@@ -1,4 +1,4 @@
@import "../css//variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.ConvertElementTypePopup {
+1 -1
View File
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.Dialog {
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.ElementLinkDialog {
@@ -59,7 +59,7 @@
}
.ElementLinkDialog__remove {
color: $oc-red-9;
color: $color-red-9;
margin-left: 1rem;
.ToolIcon__icon {
@@ -68,7 +68,7 @@
}
.ToolIcon__icon svg {
color: $oc-red-6;
color: $color-red-6;
}
}
}
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.ExportDialog__preview {
@@ -112,7 +112,7 @@
font-family: Cascadia;
font-size: 1.8em;
color: $oc-white;
color: #fff;
&:hover {
background-color: var(--button-color-darker);
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
@keyframes successStatusAnimation {
0% {
@@ -24,6 +24,14 @@
background-color: var(--back-color);
border-color: var(--border-color);
border-radius: 0.5rem;
border-width: 1px;
border-style: solid;
font-family: var(--font-family);
user-select: none;
&:hover {
transition: all 150ms ease-out;
}
@@ -266,14 +274,6 @@
}
}
border-radius: 0.5rem;
border-width: 1px;
border-style: solid;
font-family: var(--font-family);
user-select: none;
&--size-large {
font-weight: 600;
font-size: 0.875rem;
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.FixedSideContainer {
@@ -1,4 +1,4 @@
@import "../../css/variables.module.scss";
@use "../../css/variables.module" as *;
.excalidraw {
.FontPicker__container {
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.HelpDialog {
@@ -60,11 +60,12 @@
&__islands-container {
display: grid;
grid-column-gap: 1.5rem;
grid-row-gap: 2rem;
@media screen and (min-width: 1024px) {
grid-template-columns: 1fr 1fr;
}
grid-column-gap: 1.5rem;
grid-row-gap: 2rem;
}
@media screen and (min-width: 1024px) {
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
// this is loosely based on the longest hint text
$wide-viewport-width: 1000px;
@@ -1,10 +1,11 @@
@import "../css/variables.module.scss";
@use "sass:color";
@use "../css/variables.module" as *;
.excalidraw {
.picker {
padding: 0.5rem;
background: var(--popup-bg-color);
border: 0 solid transparentize($oc-white, 0.75);
border: 0 solid color.adjust(#fff, $alpha: -0.75);
box-shadow: var(--shadow-island);
border-radius: 4px;
position: absolute;
@@ -87,7 +88,7 @@
}
.picker-type-elementBackground .picker-keybinding {
color: $oc-white;
color: #fff;
}
.picker-swatch[aria-label="transparent"] .picker-keybinding {
@@ -100,10 +101,10 @@
&.theme--dark {
.picker-type-elementBackground .picker-keybinding {
color: $oc-black;
color: #000;
}
.picker-swatch[aria-label="transparent"] .picker-keybinding {
color: $oc-black;
color: #000;
}
}
}
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
--ImageExportModal-preview-border: #d6d6d6;
+1 -2
View File
@@ -1,5 +1,4 @@
@import "open-color/open-color";
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.layer-ui__wrapper.animate {
@@ -1,4 +1,4 @@
@import "open-color/open-color";
@use "../css/variables.module" as *;
.excalidraw {
.layer-ui__library {
@@ -46,15 +46,15 @@
}
&-close.ToolIcon_type_button {
background-color: $oc-blue-6;
background-color: $color-blue-6;
align-self: flex-end;
&:hover {
background-color: $oc-blue-8;
background-color: $color-blue-8;
}
.ToolIcon__icon {
width: auto;
font-size: 1rem;
color: $oc-white;
color: #fff;
padding: 0 0.5rem;
}
}
@@ -90,7 +90,7 @@
border-radius: var(--border-radius-lg);
background-color: var(--color-primary);
color: $oc-white;
color: #fff;
text-align: center;
white-space: nowrap;
text-decoration: none !important;
@@ -1,4 +1,4 @@
@import "open-color/open-color";
@use "../css/variables.module" as *;
.excalidraw {
--container-padding-y: 1rem;
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.library-unit {
@@ -1,5 +1,4 @@
@import "open-color/open-color.scss";
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.mobile-toolbar {
+1 -1
View File
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
&.excalidraw-modal-container {
@@ -1,4 +1,4 @@
@import "../../css/variables.module.scss";
@use "../../css/variables.module" as *;
.excalidraw {
.OverwriteConfirm {
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.PasteChartDialog {
@@ -25,7 +25,7 @@
height: 128px;
border-radius: 2px;
padding: 1px;
border: 1px solid $oc-gray-4;
border: 1px solid $color-gray-4;
display: flex;
align-items: center;
justify-content: center;
@@ -39,7 +39,7 @@
}
&:hover {
padding: 0;
border: 2px solid $oc-blue-5;
border: 2px solid $color-blue-5;
}
}
}
@@ -1,4 +1,3 @@
import oc from "open-color";
import React, { useLayoutEffect, useRef, useState } from "react";
import type { ChartType } from "@excalidraw/element/types";
@@ -49,7 +48,7 @@ const ChartPreviewBtn = (props: {
elements,
{
exportBackground: false,
viewBackgroundColor: oc.white,
viewBackgroundColor: "#fff",
},
null, // files
{
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.publish-library {
@@ -14,7 +14,7 @@
span {
font-weight: 500;
font-size: 1rem;
color: $oc-gray-6;
color: $color-gray-6;
}
input,
textarea {
@@ -24,7 +24,7 @@
}
.required {
color: $oc-red-8;
color: $color-red-8;
margin: 0.2rem;
}
}
@@ -48,22 +48,22 @@
}
&--confirm.ToolIcon_type_button {
background-color: $oc-blue-6;
background-color: $color-blue-6;
&:hover {
background-color: $oc-blue-8;
background-color: $color-blue-8;
}
}
&--cancel.ToolIcon_type_button {
background-color: $oc-gray-5;
background-color: $color-gray-5;
&:hover {
background-color: $oc-gray-6;
background-color: $color-gray-6;
}
}
.ToolIcon__icon {
color: $oc-white;
color: #fff;
.Spinner {
--spinner-color: #fff;
svg {
@@ -83,7 +83,7 @@
}
&-warning {
color: $oc-red-6;
color: $color-red-6;
}
&-note {
@@ -102,14 +102,14 @@
top: 0.3rem;
left: 0.3rem;
font-size: 0.7rem;
color: $oc-red-7;
color: $color-red-7;
background: rgba(255, 255, 255, 0.9);
padding: 0.1rem 0.2rem;
border-radius: 0.2rem;
}
&__svg {
background-color: $oc-white;
background-color: #fff;
padding: 0.3rem;
width: 7.5rem;
height: 7.5rem;
@@ -121,7 +121,7 @@
}
.ToolIcon__icon {
background-color: $oc-white;
background-color: #fff;
width: auto;
height: auto;
margin: 0 0.5rem;
@@ -132,7 +132,7 @@
}
.required,
.error {
color: $oc-red-8;
color: $color-red-8;
font-weight: 700;
font-size: 1rem;
margin: 0.2rem;
@@ -152,16 +152,16 @@
margin: 0;
}
.ToolIcon__icon {
background-color: $oc-red-6;
background-color: $color-red-6;
&:hover {
background-color: $oc-red-7;
background-color: $color-red-7;
}
&:active {
background-color: $oc-red-8;
background-color: $color-red-8;
}
}
svg {
color: $oc-white;
color: #fff;
padding: 0.26rem;
border-radius: 0.3em;
width: 1rem;
@@ -1,5 +1,4 @@
import { exportToCanvas, exportToSvg } from "@excalidraw/utils/export";
import OpenColor from "open-color";
import { useCallback, useEffect, useRef, useState } from "react";
import {
@@ -57,7 +56,7 @@ const generatePreviewImage = async (libraryItems: LibraryItems) => {
const ctx = canvas.getContext("2d")!;
ctx.fillStyle = OpenColor.white;
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// draw items
@@ -87,7 +86,7 @@ const generatePreviewImage = async (libraryItems: LibraryItems) => {
// draw item border
// -------------------------------------------------------------------------
ctx.lineWidth = BORDER_WIDTH;
ctx.strokeStyle = OpenColor.gray[4];
ctx.strokeStyle = "#ced4da";
ctx.strokeRect(
colOffset + BOX_PADDING / 2,
rowOffset + BOX_PADDING / 2,
@@ -131,7 +130,7 @@ const SingleLibraryItem = ({
elements: libItem.elements,
appState: {
...appState,
viewBackgroundColor: OpenColor.white,
viewBackgroundColor: "#fff",
exportBackground: true,
},
files: null,
@@ -175,7 +174,7 @@ const SingleLibraryItem = ({
}}
>
<div style={{ padding: "0.5em 0" }}>
<span style={{ fontWeight: 500, color: OpenColor.gray[6] }}>
<span style={{ fontWeight: 500, color: "#868e96" }}>
{t("publishDialog.itemName")}
</span>
<span aria-hidden="true" className="required">
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
--RadioGroup-background: var(--island-bg-color);
+1 -1
View File
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
--slider-thumb-size: 16px;
+1 -1
View File
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.SVGLayer {
@@ -1,5 +1,4 @@
@import "open-color/open-color";
@import "../css//variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.layer-ui__search {
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.ShareableLinkDialog {
@@ -1,5 +1,4 @@
@import "open-color/open-color";
@import "../../css/variables.module.scss";
@use "../../css/variables.module" as *;
.excalidraw {
.sidebar {
@@ -19,6 +18,12 @@
pointer-events: var(--ui-pointerEvents);
overflow: hidden;
border-radius: 0;
width: calc(var(--right-sidebar-width) - var(--space-factor) * 2);
border-left: 1px solid var(--sidebar-border-color);
:root[dir="rtl"] & {
left: 0;
right: auto;
@@ -28,12 +33,6 @@
box-shadow: none;
}
overflow: hidden;
border-radius: 0;
width: calc(var(--right-sidebar-width) - var(--space-factor) * 2);
border-left: 1px solid var(--sidebar-border-color);
:root[dir="rtl"] & {
border-right: 1px solid var(--sidebar-border-color);
border-left: 0;
@@ -1,4 +1,4 @@
@import "../../css/variables.module.scss";
@use "../../css/variables.module" as *;
.excalidraw {
.sidebar-trigger {
+1 -1
View File
@@ -1,4 +1,4 @@
@import "open-color/open-color.scss";
@use "../css/variables.module" as *;
$duration: 1.6s;
+1 -1
View File
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
--Switch-disabled-color: var(--color-border-outline);
@@ -1,4 +1,4 @@
@import "../../css/variables.module.scss";
@use "../../css/variables.module" as *;
$verticalBreakpoint: 861px;
@@ -241,7 +241,7 @@ $verticalBreakpoint: 861px;
height: 2.5rem;
font-size: 12px;
color: $oc-white;
color: #fff;
background-color: var(--color-primary);
width: 100%;
@@ -271,7 +271,9 @@ $verticalBreakpoint: 861px;
}
}
position: relative;
& {
position: relative;
}
div {
display: contents;
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
--ExcTextField--color: var(--color-on-surface);
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.TextInput {
+1 -1
View File
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.Toast {
+1 -2
View File
@@ -1,5 +1,4 @@
@import "open-color/open-color.scss";
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.ToolIcon {
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.tool-popover-content {
+1 -2
View File
@@ -1,5 +1,4 @@
@import "open-color/open-color.scss";
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.App-toolbar {
+3 -3
View File
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
// container in body where the actual tooltip is appended to
.excalidraw-tooltip {
@@ -14,13 +14,13 @@
pointer-events: none;
word-wrap: break-word;
background: $oc-black;
background: #000;
line-height: 1.5;
text-align: center;
font-size: 13px;
font-weight: 500;
color: $oc-white;
color: #fff;
display: none;
@@ -1,4 +1,4 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
.UnlockPopup {
+23 -20
View File
@@ -1,10 +1,22 @@
@import "../css/variables.module.scss";
@use "../css/variables.module" as *;
.excalidraw {
--avatar-size: 1.75rem;
--avatarList-gap: 0.625rem;
--userList-padding: var(--space-factor);
--userlist-hint-bg-color: var(--color-gray-10);
--userlist-hint-heading-color: var(--color-gray-80);
--userlist-hint-text-color: var(--color-gray-60);
--userlist-collaborators-border-color: var(--color-gray-20);
&.theme--dark {
--userlist-hint-bg-color: var(--color-gray-90);
--userlist-hint-heading-color: var(--color-gray-30);
--userlist-hint-text-color: var(--color-gray-40);
--userlist-collaborators-border-color: var(--color-gray-80);
}
.UserList__wrapper {
display: flex;
width: 100%;
@@ -50,13 +62,16 @@
.UserList__more {
@include avatarStyles;
background-color: var(--color-gray-20);
border: 0 !important;
font-size: 0.625rem;
font-weight: 400;
flex-shrink: 0;
color: var(--color-gray-100);
font-weight: bold;
& {
background-color: var(--color-gray-20);
border: 0 !important;
font-size: 0.625rem;
font-weight: 400;
flex-shrink: 0;
color: var(--color-gray-100);
font-weight: bold;
}
}
.UserList__collaborator-name {
@@ -141,18 +156,6 @@
}
}
--userlist-hint-bg-color: var(--color-gray-10);
--userlist-hint-heading-color: var(--color-gray-80);
--userlist-hint-text-color: var(--color-gray-60);
--userlist-collaborators-border-color: var(--color-gray-20);
&.theme--dark {
--userlist-hint-bg-color: var(--color-gray-90);
--userlist-hint-heading-color: var(--color-gray-30);
--userlist-hint-text-color: var(--color-gray-40);
--userlist-collaborators-border-color: var(--color-gray-80);
}
.UserList__collaborators {
top: auto;
max-height: 50vh;
@@ -1,4 +1,4 @@
@import "../../css/variables.module.scss";
@use "../../css/variables.module" as *;
.excalidraw {
.dropdown-menu {
@@ -1,11 +1,12 @@
.footer-center {
pointer-events: none;
& > * {
pointer-events: var(--ui-pointerEvents);
}
display: flex;
width: 100%;
justify-content: flex-start;
margin-inline-end: 0.6rem;
& > * {
pointer-events: var(--ui-pointerEvents);
}
}
@@ -1,4 +1,4 @@
@import "../../css/variables.module.scss";
@use "../../css/variables.module" as *;
.excalidraw-hyperlinkContainer {
display: flex;
@@ -47,16 +47,16 @@
}
button {
color: $oc-blue-6;
color: $color-blue-6;
background-color: transparent !important;
font-weight: 500;
&.excalidraw-hyperlinkContainer--remove {
color: $oc-red-9;
color: $color-red-9;
}
}
&--remove .ToolIcon__icon svg {
color: $oc-red-6;
color: $color-red-6;
}
.ToolIcon__icon {
+1 -2
View File
@@ -7,7 +7,6 @@
// to determine whether or not the icons should be mirrored in right-to-left languages.
import clsx from "clsx";
import oc from "open-color";
import React from "react";
import { THEME } from "@excalidraw/common";
@@ -17,7 +16,7 @@ import type { Theme } from "@excalidraw/element/types";
export const iconFillColor = (theme: Theme) => "var(--icon-fill-color)";
const handlerColor = (theme: Theme) =>
theme === THEME.LIGHT ? oc.white : "#1e1e1e";
theme === THEME.LIGHT ? "#fff" : "#1e1e1e";
type Opts = {
width?: number;
@@ -1,4 +1,4 @@
@import "../../css/variables.module.scss";
@use "../../css/variables.module" as *;
.excalidraw {
.collab-button {
@@ -58,8 +58,8 @@
bottom: -5px;
padding: 3px;
border-radius: 50%;
background-color: $oc-green-2;
color: $oc-green-9;
background-color: $color-green-2;
color: $color-green-9;
font-size: 0.6rem;
font-family: "Cascadia";
}
-2
View File
@@ -1,5 +1,3 @@
@import "open-color/open-color.scss";
.visually-hidden {
position: absolute !important;
height: 1px;
+5 -5
View File
@@ -1,5 +1,5 @@
@import "./variables.module.scss";
@import "./theme";
@use "./variables.module" as *;
@use "./theme";
:root {
--zIndex-canvas: 1;
@@ -210,7 +210,7 @@ body.excalidraw-cursor-resize * {
.divider {
width: 1px;
background-color: $oc-gray-2;
background-color: $color-gray-2;
margin: 1px;
}
@@ -729,8 +729,8 @@ body.excalidraw-cursor-resize * {
justify-content: center;
padding: 40px;
background-color: $oc-red-1;
border: 3px solid $oc-red-9;
background-color: $color-red-1;
border: 3px solid $color-red-9;
}
.ErrorSplash-paragraph {
+44 -43
View File
@@ -1,35 +1,36 @@
@import "open-color/open-color.scss";
@import "./variables.module.scss";
@use "sass:color";
@use "./variables.module" as *;
@forward "./variables.module";
.excalidraw {
--theme-filter: none;
--button-destructive-bg-color: #{$oc-red-1};
--button-destructive-color: #{$oc-red-9};
--button-gray-1: #{$oc-gray-2};
--button-gray-2: #{$oc-gray-4};
--button-gray-3: #{$oc-gray-5};
--button-destructive-bg-color: #{$color-red-1};
--button-destructive-color: #{$color-red-9};
--button-gray-1: #{$color-gray-2};
--button-gray-2: #{$color-gray-4};
--button-gray-3: #{$color-gray-5};
--mobile-action-button-bg: rgba(255, 255, 255, 0.35);
--mobile-color-border: var(--default-border-color);
--button-special-active-bg-color: #{$oc-green-0};
--button-special-active-bg-color: #{$color-green-0};
--dialog-border-color: var(--color-gray-20);
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
--focus-highlight-color: #{$oc-blue-2};
--focus-highlight-color: #{$color-blue-2};
--icon-fill-color: var(--color-on-surface);
--icon-green-fill-color: #{$oc-green-9};
--default-bg-color: #{$oc-white};
--input-bg-color: #{$oc-white};
--input-border-color: #{$oc-gray-4};
--input-hover-bg-color: #{$oc-gray-1};
--input-label-color: #{$oc-gray-7};
--icon-green-fill-color: #{$color-green-9};
--default-bg-color: #fff;
--input-bg-color: #fff;
--input-border-color: #{$color-gray-4};
--input-hover-bg-color: #{$color-gray-1};
--input-label-color: #{$color-gray-7};
--island-bg-color: #ffffff;
--keybinding-color: var(--color-gray-40);
--link-color: #{$oc-blue-7};
--overlay-bg-color: #{transparentize($oc-white, 0.12)};
--link-color: #{$color-blue-7};
--overlay-bg-color: #{color.adjust(#fff, $alpha: -0.12)};
--popup-bg-color: var(--island-bg-color);
--popup-secondary-bg-color: #{$oc-gray-1};
--popup-text-color: #{$oc-black};
--popup-text-inverted-color: #{$oc-white};
--select-highlight-color: #{$oc-blue-5};
--popup-secondary-bg-color: #{$color-gray-1};
--popup-text-color: #000;
--popup-text-inverted-color: #fff;
--select-highlight-color: #{$color-blue-5};
--shadow-island: 0px 0px 0.9310142993927002px 0px rgba(0, 0, 0, 0.17),
0px 0px 3.1270833015441895px 0px rgba(0, 0, 0, 0.08),
0px 7px 14px 0px rgba(0, 0, 0, 0.05);
@@ -46,17 +47,6 @@
--editor-container-padding: 1rem;
--mobile-action-button-size: 2rem;
@include isMobile {
--editor-container-padding: 0.75rem;
}
@media screen and (min-device-width: 1921px) {
--lg-button-size: 2.5rem;
--lg-icon-size: 1.25rem;
--default-button-size: 2.25rem;
--default-icon-size: 1.25rem;
}
--scrollbar-thumb: var(--button-gray-2);
--scrollbar-thumb-hover: var(--button-gray-3);
@@ -87,7 +77,7 @@
--color-selection: #6965db;
--color-icon-white: #{$oc-white};
--color-icon-white: #fff;
--color-primary: #6965db;
--color-primary-darker: #5b57d1;
@@ -170,6 +160,17 @@
--color-badge: #0b6513;
--background-color-badge: #d3ffd2;
@include isMobile {
--editor-container-padding: 0.75rem;
}
@media screen and (min-device-width: 1921px) {
--lg-button-size: 2.5rem;
--lg-icon-size: 1.25rem;
--default-button-size: 2.25rem;
--default-icon-size: 1.25rem;
}
&.theme--dark {
&.theme--dark-background-none {
background: none;
@@ -179,7 +180,7 @@
&.theme--dark {
--theme-filter: invert(93%) hue-rotate(180deg);
--button-destructive-bg-color: #5a0000;
--button-destructive-color: #{$oc-red-3};
--button-destructive-color: #{$color-red-3};
--button-gray-1: #363636;
--button-gray-2: #272727;
@@ -189,21 +190,21 @@
--button-special-active-bg-color: #204624;
--dialog-border-color: var(--color-gray-80);
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path fill="%23ced4da" d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
--focus-highlight-color: #{$oc-blue-6};
--icon-green-fill-color: #{$oc-green-4};
--focus-highlight-color: #{$color-blue-6};
--icon-green-fill-color: #{$color-green-4};
--default-bg-color: #121212;
--input-bg-color: #121212;
--input-border-color: #2e2e2e;
--input-hover-bg-color: #181818;
--input-label-color: #{$oc-gray-2};
--input-label-color: #{$color-gray-2};
--island-bg-color: #232329;
--keybinding-color: var(--color-gray-60);
--link-color: #{$oc-blue-4};
--overlay-bg-color: #{transparentize($oc-gray-8, 0.88)};
--link-color: #{$color-blue-4};
--overlay-bg-color: #{color.adjust($color-gray-8, $alpha: -0.88)};
--popup-secondary-bg-color: #222;
--popup-text-color: #{$oc-gray-4};
--popup-text-color: #{$color-gray-4};
--popup-text-inverted-color: #2c2c2c;
--select-highlight-color: #{$oc-blue-4};
--select-highlight-color: #{$color-blue-4};
--shadow-island: 0px 0px 0.9310142993927002px 0px rgba(0, 0, 0, 0.17),
0px 0px 3.1270833015441895px 0px rgba(0, 0, 0, 0.08),
0px 7px 14px 0px rgba(0, 0, 0, 0.05);
@@ -216,8 +217,8 @@
0px 2.76726px 2.21381px rgba(0, 0, 0, 0.0196802);
--avatar-border-color: var(--color-gray-85);
--scrollbar-thumb: #{$oc-gray-8};
--scrollbar-thumb-hover: #{$oc-gray-7};
--scrollbar-thumb: #{$color-gray-8};
--scrollbar-thumb-hover: #{$color-gray-7};
--color-slider-track: hsl(244, 23%, 39%);
+28 -2
View File
@@ -1,4 +1,27 @@
@import "open-color/open-color.scss";
$color-red-1: #ffe3e3;
$color-red-3: #ffa8a8;
$color-red-6: #fa5252;
$color-red-7: #f03e3e;
$color-red-8: #e03131;
$color-red-9: #c92a2a;
$color-gray-1: #f1f3f5;
$color-gray-2: #e9ecef;
$color-gray-4: #ced4da;
$color-gray-5: #adb5bd;
$color-gray-6: #868e96;
$color-gray-7: #495057;
$color-gray-8: #343a40;
$color-green-0: #ebfbee;
$color-green-2: #b2f2bb;
$color-green-4: #69db7c;
$color-green-9: #2b8a3e;
$color-blue-1: #d0ebff;
$color-blue-2: #a5d8ff;
$color-blue-4: #4dabf7;
$color-blue-5: #339af0;
$color-blue-6: #228be6;
$color-blue-7: #1c7ed6;
$color-blue-8: #1971c2;
@mixin isMobile() {
@at-root .excalidraw--mobile#{&} {
@@ -137,7 +160,10 @@
@mixin outlineButtonIconStyles {
@include outlineButtonStyles;
padding: 0;
& {
padding: 0;
}
svg {
width: var(--default-icon-size);
+2 -4
View File
@@ -1,5 +1,3 @@
import OpenColor from "open-color";
import { CURSOR_TYPE, MIME_TYPES, THEME } from "@excalidraw/common";
import { isHandToolActive, isEraserActive } from "./appState";
@@ -60,9 +58,9 @@ export const setEraserCursor = (
0,
2 * Math.PI,
);
context.fillStyle = isDarkTheme ? OpenColor.black : OpenColor.white;
context.fillStyle = isDarkTheme ? "#000" : "#fff";
context.fill();
context.strokeStyle = isDarkTheme ? OpenColor.white : OpenColor.black;
context.strokeStyle = isDarkTheme ? "#fff" : "#000";
context.stroke();
previewDataURL = eraserCanvasCache.toDataURL(MIME_TYPES.svg) as DataURL;
};
-1
View File
@@ -100,7 +100,6 @@
"lodash.debounce": "4.0.8",
"lodash.throttle": "4.1.1",
"nanoid": "3.3.3",
"open-color": "1.9.1",
"pako": "2.0.3",
"perfect-freehand": "1.2.0",
"pica": "7.1.1",
@@ -6,7 +6,6 @@ import {
type LocalPoint,
type Radians,
} from "@excalidraw/math";
import oc from "open-color";
import {
arrayToMap,
@@ -1301,7 +1300,7 @@ const _renderInteractiveScene = ({
elementsMap,
);
}
const selectionColor = renderConfig.selectionColor || oc.black;
const selectionColor = renderConfig.selectionColor || "#000";
if (showBoundingBox) {
// Optimisation for finding quickly relevant element ids
@@ -1384,7 +1383,7 @@ const _renderInteractiveScene = ({
y2,
selectionColors: groupElements.some((el) => el.locked)
? ["#ced4da"]
: [oc.black],
: ["#000"],
dashed: true,
cx: x1 + (x2 - x1) / 2,
cy: y1 + (y2 - y1) / 2,
@@ -1410,7 +1409,7 @@ const _renderInteractiveScene = ({
context.translate(appState.scrollX, appState.scrollY);
if (selectedElements.length === 1) {
context.fillStyle = oc.white;
context.fillStyle = "#fff";
const transformHandles = getTransformHandles(
selectedElements[0],
appState.zoom,
@@ -1455,7 +1454,7 @@ const _renderInteractiveScene = ({
) {
const dashedLinePadding =
(DEFAULT_TRANSFORM_HANDLE_SPACING * 2) / appState.zoom.value;
context.fillStyle = oc.white;
context.fillStyle = "#fff";
const [x1, y1, x2, y2] = getCommonBounds(selectedElements, elementsMap);
const initialLineDash = context.getLineDash();
context.setLineDash([2 / appState.zoom.value]);
+1 -1
View File
@@ -1,4 +1,4 @@
import { normalizeInputColor } from "../components/ColorPicker/ColorInput";
import { normalizeInputColor } from "@excalidraw/common";
describe("normalizeInputColor", () => {
describe("hex colors", () => {
@@ -5,13 +5,13 @@ import { getOriginalContainerHeightFromCache } from "@excalidraw/element";
import {
CODES,
colorToHex,
KEYS,
FONT_FAMILY,
TEXT_ALIGN,
THEME,
VERTICAL_ALIGN,
applyDarkModeFilter,
tinycolor,
} from "@excalidraw/common";
import type {
@@ -1672,7 +1672,7 @@ describe("textWysiwyg", () => {
// Helper to compare colors (browser may return rgb format)
const colorsAreEqual = (color1: string, color2: string) => {
return tinycolor(color1).toHex() === tinycolor(color2).toHex();
return colorToHex(color1) === colorToHex(color2);
};
beforeEach(async () => {
-1
View File
@@ -51,7 +51,6 @@
"@braintree/sanitize-url": "6.0.2",
"@excalidraw/laser-pointer": "1.3.1",
"browser-fs-access": "0.29.1",
"open-color": "1.9.1",
"pako": "2.0.3",
"perfect-freehand": "1.2.0",
"png-chunk-text": "1.0.0",
+45 -1
View File
@@ -1,4 +1,6 @@
const path = require("path");
const fs = require("fs");
const { pathToFileURL } = require("url");
const { build } = require("esbuild");
const { sassPlugin } = require("esbuild-sass-plugin");
@@ -16,6 +18,44 @@ const ENV_VARS = {
},
};
// Resolve a relative path from the source file's directory
const resolveRelativePath = (importPath, sourceFile) => {
const sourceDir = path.dirname(sourceFile);
const extensions = [".scss", ".css", ""];
for (const ext of extensions) {
const fullPath = path.resolve(sourceDir, importPath + ext);
if (fs.existsSync(fullPath)) {
return fullPath;
}
// Try with underscore prefix for partials
const partialPath = path.join(
path.dirname(fullPath),
`_${path.basename(fullPath)}`,
);
if (fs.existsSync(partialPath)) {
return partialPath;
}
}
return null;
};
// Precompile function to convert relative paths to absolute paths
const precompile = (source, sourcePath) => {
// Match @use and @forward statements with relative paths
const importRegex = /(@use|@forward)\s+["'](\.[^"']+)["']/g;
return source.replace(importRegex, (match, directive, importPath) => {
const resolvedPath = resolveRelativePath(importPath, sourcePath);
if (resolvedPath) {
// Convert to file:// URL format for sass
const fileUrl = pathToFileURL(resolvedPath).href;
return `${directive} "${fileUrl}"`;
}
return match;
});
};
// excludes all external dependencies and bundles only the source code
const getConfig = (outdir) => ({
outdir,
@@ -23,7 +63,11 @@ const getConfig = (outdir) => ({
splitting: true,
format: "esm",
packages: "external",
plugins: [sassPlugin()],
plugins: [
sassPlugin({
precompile,
}),
],
target: "es2020",
assetNames: "[dir]/[name]",
chunkNames: "[dir]/[name]-[hash]",
-5
View File
@@ -7616,11 +7616,6 @@ onetime@^5.1.0, onetime@^5.1.2:
dependencies:
mimic-fn "^2.1.0"
open-color@1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/open-color/-/open-color-1.9.1.tgz#a6e6328f60eff7aa60e3e8fcfa50f53ff3eece35"
integrity sha512-vCseG/EQ6/RcvxhUcGJiHViOgrtz4x0XbZepXvKik66TMGkvbmjeJrKFyBEx6daG5rNyyd14zYXhz0hZVwQFOw==
opener@^1.5.1:
version "1.5.2"
resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598"