From 33721492771919e8569964fe0b034a9cf7f25955 Mon Sep 17 00:00:00 2001 From: David Luzar <5153846+dwelle@users.noreply.github.com> Date: Mon, 1 Jun 2026 15:43:45 +0200 Subject: [PATCH] feat(packages/excalidraw): export applyDarkModeFilter and simplify (#11429) --- packages/common/src/colors.ts | 6 ++++- packages/element/src/renderElement.ts | 24 +++++++++---------- packages/element/src/shape.ts | 23 +++++++----------- packages/excalidraw/components/App.tsx | 7 +++--- packages/excalidraw/index.tsx | 3 +++ packages/excalidraw/renderer/helpers.ts | 8 +++---- .../excalidraw/renderer/staticSvgScene.ts | 21 +++++++++------- packages/excalidraw/scene/export.ts | 4 +--- packages/excalidraw/wysiwyg/textWysiwyg.tsx | 8 +++---- 9 files changed, 53 insertions(+), 51 deletions(-) diff --git a/packages/common/src/colors.ts b/packages/common/src/colors.ts index 567093c7d9..f6bced8b67 100644 --- a/packages/common/src/colors.ts +++ b/packages/common/src/colors.ts @@ -80,7 +80,11 @@ const cssInvert = ( return { r: invertedR, g: invertedG, b: invertedB }; }; -export const applyDarkModeFilter = (color: string): string => { +export const applyDarkModeFilter = (color: string, enable = true): string => { + if (!enable) { + return color; + } + const cached = DARK_MODE_COLORS_CACHE?.get(color); if (cached) { return cached; diff --git a/packages/element/src/renderElement.ts b/packages/element/src/renderElement.ts index 96bff999bc..d5e4ca259a 100644 --- a/packages/element/src/renderElement.ts +++ b/packages/element/src/renderElement.ts @@ -422,10 +422,10 @@ const drawElementOnCanvas = ( for (const shape of shapes) { if (typeof shape === "string") { - context.fillStyle = - renderConfig.theme === THEME.DARK - ? applyDarkModeFilter(element.strokeColor) - : element.strokeColor; + context.fillStyle = applyDarkModeFilter( + element.strokeColor, + renderConfig.theme === THEME.DARK, + ); context.fill(new Path2D(shape)); } else { rc.draw(shape); @@ -555,10 +555,10 @@ const drawElementOnCanvas = ( context.canvas.setAttribute("dir", rtl ? "rtl" : "ltr"); context.save(); context.font = getFontString(element); - context.fillStyle = - renderConfig.theme === THEME.DARK - ? applyDarkModeFilter(element.strokeColor) - : element.strokeColor; + context.fillStyle = applyDarkModeFilter( + element.strokeColor, + renderConfig.theme === THEME.DARK, + ); context.textAlign = element.textAlign as CanvasTextAlign; // Canvas does not support multiline text by default @@ -811,10 +811,10 @@ export const renderElement = ( context.fillStyle = "rgba(0, 0, 200, 0.04)"; context.lineWidth = FRAME_STYLE.strokeWidth / appState.zoom.value; - context.strokeStyle = - appState.theme === THEME.DARK - ? applyDarkModeFilter(FRAME_STYLE.strokeColor) - : FRAME_STYLE.strokeColor; + context.strokeStyle = applyDarkModeFilter( + FRAME_STYLE.strokeColor, + appState.theme === THEME.DARK, + ); // TODO change later to only affect AI frames if (isMagicFrameElement(element)) { diff --git a/packages/element/src/shape.ts b/packages/element/src/shape.ts index 158ace7519..3209c4c89d 100644 --- a/packages/element/src/shape.ts +++ b/packages/element/src/shape.ts @@ -218,9 +218,7 @@ export const generateRoughOptions = ( fillWeight: element.strokeWidth / 2, hachureGap: element.strokeWidth * 4, roughness: adjustRoughness(element), - stroke: isDarkMode - ? applyDarkModeFilter(element.strokeColor) - : element.strokeColor, + stroke: applyDarkModeFilter(element.strokeColor, isDarkMode), preserveVertices: continuousPath || element.roughness < ROUGHNESS.cartoonist, }; @@ -234,9 +232,7 @@ export const generateRoughOptions = ( options.fillStyle = element.fillStyle; options.fill = isTransparent(element.backgroundColor) ? undefined - : isDarkMode - ? applyDarkModeFilter(element.backgroundColor) - : element.backgroundColor; + : applyDarkModeFilter(element.backgroundColor, isDarkMode); if (element.type === "ellipse") { options.curveFitting = 1; } @@ -249,9 +245,7 @@ export const generateRoughOptions = ( options.fill = element.backgroundColor === "transparent" ? undefined - : isDarkMode - ? applyDarkModeFilter(element.backgroundColor) - : element.backgroundColor; + : applyDarkModeFilter(element.backgroundColor, isDarkMode); } return options; } @@ -386,12 +380,11 @@ const getArrowheadShapes = ( return []; } - const strokeColor = isDarkMode - ? applyDarkModeFilter(element.strokeColor) - : element.strokeColor; - const backgroundFillColor = isDarkMode - ? applyDarkModeFilter(canvasBackgroundColor) - : canvasBackgroundColor; + const strokeColor = applyDarkModeFilter(element.strokeColor, isDarkMode); + const backgroundFillColor = applyDarkModeFilter( + canvasBackgroundColor, + isDarkMode, + ); const cardinalityOneOrManyOffset = -0.25; const cardinalityZeroCircleScale = 0.8; diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 2317ffc4f0..899b98af19 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -1995,9 +1995,10 @@ class App extends React.Component { } }} style={{ - background: isDarkTheme - ? applyDarkModeFilter(this.state.viewBackgroundColor) - : this.state.viewBackgroundColor, + background: applyDarkModeFilter( + this.state.viewBackgroundColor, + isDarkTheme, + ), zIndex: 2, border: "none", display: "block", diff --git a/packages/excalidraw/index.tsx b/packages/excalidraw/index.tsx index 64cedb3a8e..b56e568b60 100644 --- a/packages/excalidraw/index.tsx +++ b/packages/excalidraw/index.tsx @@ -7,6 +7,7 @@ import React, { } from "react"; import { + applyDarkModeFilter, DEFAULT_IMAGE_OPTIONS, DEFAULT_UI_OPTIONS, isShallowEqual, @@ -450,3 +451,5 @@ export function useExcalidrawStateValue( // ----------------------------------------------------------------------------- export { _useOnAppStateChange as useOnExcalidrawStateChange }; + +export { applyDarkModeFilter }; diff --git a/packages/excalidraw/renderer/helpers.ts b/packages/excalidraw/renderer/helpers.ts index 8fd70428f0..e5025dcd09 100644 --- a/packages/excalidraw/renderer/helpers.ts +++ b/packages/excalidraw/renderer/helpers.ts @@ -62,10 +62,10 @@ export const bootstrapCanvas = ({ context.clearRect(0, 0, normalizedWidth, normalizedHeight); } context.save(); - context.fillStyle = - theme === THEME.DARK - ? applyDarkModeFilter(viewBackgroundColor) - : viewBackgroundColor; + context.fillStyle = applyDarkModeFilter( + viewBackgroundColor, + theme === THEME.DARK, + ); context.fillRect(0, 0, normalizedWidth, normalizedHeight); context.restore(); } else { diff --git a/packages/excalidraw/renderer/staticSvgScene.ts b/packages/excalidraw/renderer/staticSvgScene.ts index de9be13c83..85a92c7365 100644 --- a/packages/excalidraw/renderer/staticSvgScene.ts +++ b/packages/excalidraw/renderer/staticSvgScene.ts @@ -386,9 +386,10 @@ const renderElementToSvg = ( const path = svgRoot.ownerDocument.createElementNS(SVG_NS, "path"); path.setAttribute( "fill", - renderConfig.theme === THEME.DARK - ? applyDarkModeFilter(element.strokeColor) - : element.strokeColor, + applyDarkModeFilter( + element.strokeColor, + renderConfig.theme === THEME.DARK, + ), ); path.setAttribute("d", shape); wrapper.appendChild(path); @@ -621,9 +622,10 @@ const renderElementToSvg = ( rect.setAttribute("fill", "none"); rect.setAttribute( "stroke", - renderConfig.theme === THEME.DARK - ? applyDarkModeFilter(FRAME_STYLE.strokeColor) - : FRAME_STYLE.strokeColor, + applyDarkModeFilter( + FRAME_STYLE.strokeColor, + renderConfig.theme === THEME.DARK, + ), ); rect.setAttribute("stroke-width", FRAME_STYLE.strokeWidth.toString()); @@ -677,9 +679,10 @@ const renderElementToSvg = ( text.setAttribute("font-size", `${element.fontSize}px`); text.setAttribute( "fill", - renderConfig.theme === THEME.DARK - ? applyDarkModeFilter(element.strokeColor) - : element.strokeColor, + applyDarkModeFilter( + element.strokeColor, + renderConfig.theme === THEME.DARK, + ), ); text.setAttribute("text-anchor", textAnchor); text.setAttribute("style", "white-space: pre;"); diff --git a/packages/excalidraw/scene/export.ts b/packages/excalidraw/scene/export.ts index 8d8c405e82..eef553d4c7 100644 --- a/packages/excalidraw/scene/export.ts +++ b/packages/excalidraw/scene/export.ts @@ -459,9 +459,7 @@ export const exportToSvg = async ( rect.setAttribute("height", `${height}`); rect.setAttribute( "fill", - exportWithDarkMode - ? applyDarkModeFilter(viewBackgroundColor) - : viewBackgroundColor, + applyDarkModeFilter(viewBackgroundColor, exportWithDarkMode), ); svgRoot.appendChild(rect); } diff --git a/packages/excalidraw/wysiwyg/textWysiwyg.tsx b/packages/excalidraw/wysiwyg/textWysiwyg.tsx index 262558727c..eeee206fa7 100644 --- a/packages/excalidraw/wysiwyg/textWysiwyg.tsx +++ b/packages/excalidraw/wysiwyg/textWysiwyg.tsx @@ -392,10 +392,10 @@ export const textWysiwyg = ({ ), textAlign, verticalAlign, - color: - appState.theme === THEME.DARK - ? applyDarkModeFilter(updatedTextElement.strokeColor) - : updatedTextElement.strokeColor, + color: applyDarkModeFilter( + updatedTextElement.strokeColor, + appState.theme === THEME.DARK, + ), opacity: updatedTextElement.opacity / 100, maxHeight: `${editorMaxHeight}px`, });