Skip to content

fix: color utils get css color from theme mode - #331

Merged
bdjulbic merged 6 commits into
mainfrom
fix/color-utils-getCssColorFromThemeMode
Feb 3, 2026
Merged

bdjulbic merged 6 commits into
mainfrom
fix/color-utils-getCssColorFromThemeMode

Conversation

@bdjulbic

@bdjulbic bdjulbic commented Jan 28, 2026 •

Copy link
Copy Markdown
Collaborator

After the previous PR merge regarding Monaco editor flashing,
an issue appeared where theme colors weren't getting resolved properly.

This PR rollbacks file color-utils.ts,
and instead makes sure the theme is once defined in MonacoEditor, instead of getting redefined every time MonacoEditor was created which caused the initial issue with flashing

Example of editor background, before the color was #09090b (very dark) and after update its #020817 (blueish black)
Screenshot 2026-01-28 at 12 22 12

Summary by CodeRabbit

  • New Features

    • Monaco editor themes now apply and update dynamically when the app theme, editor settings, or language change.
    • Query editor instances are now identified per query for improved instance tracking.
  • Refactor

    • Color resolution streamlined to read live CSS variables from the DOM for consistent theming.
    • Internal theme setup simplified and consolidated; public editor props remain unchanged.
  • Bug Fixes

    • Prevents redundant theme redefinitions to reduce flicker and improve stability.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@bdjulbic bdjulbic changed the title Fix/color utils get css color from theme mode fix/color utils get css color from theme mode Jan 28, 2026
@bdjulbic bdjulbic changed the title fix/color utils get css color from theme mode fix: color utils get css color from theme mode Jan 28, 2026
* @param currentMatch - The last match found so far (used internally for recursion to accumulate results across nested rules)
* @returns The last matching CSS variable value, or undefined if not found
*/
function walkCssRulesForVariable(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this PR affect this?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most probably it will,
I updated some projects from tailwind 3 to tailwind 4 and it was never a smooth ride.

So ill wait for that PR to merge?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe @dmitriy-kostianetskiy can comment

@ilyabo

ilyabo commented Feb 2, 2026

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Feb 2, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Feb 2, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Removes stylesheet/element-based CSS variable helpers and centralizes runtime DOM reads for color resolution; simplifies signatures for getMenuColors and getJsonEditorTheme; consolidates Monaco theme definitions via defineMonacoThemes, adds monacoRef and a module-level dark-mode guard, and reapplies themes on mount and when theme or language change. Also adds a path prop to a SQL editor instance for query identification.

Changes

Cohort / File(s) Summary
Color utils
packages/monaco-editor/src/utils/color-utils.ts
Removed helper functions that read CSS vars from stylesheets/elements/theme modes (getRawCssVarFromStylesheets, getCssColorFromThemeMode, getCssColorFromElement); getCssColor now reads live DOM; simplified signatures for getMenuColors and getJsonEditorTheme.
Monaco theming & init
packages/monaco-editor/src/components/MonacoEditor.tsx
Replaced old theme setup with defineMonacoThemes(monaco, isDark, currentTheme), added monacoRef and lastDefinedForDarkMode guard, switched color lookups to getCssColor, explicitly registers light/dark/json themes, and re-runs theme defs on mount and when isDark, monacoTheme, or language change.
SQL editor instance id
packages/sql-editor/src/components/QueryEditorPanelEditor.tsx
Sets path prop on SqlMonacoEditor to sqlrooms:query:${queryId} to uniquely identify the editor instance for a query.

Sequence Diagram(s)

sequenceDiagram
  participant App as React App
  participant ME as MonacoEditor
  participant DOM as document (CSS vars)
  participant Monaco as monaco.editor

  App->>ME: render(props: isDark, monacoTheme, language)
  ME->>ME: beforeMount / onMount
  ME->>DOM: getCssColor(...) — read CSS variables from document.documentElement
  ME->>Monaco: defineMonacoThemes(monaco, isDark, monacoTheme)
  Monaco-->>ME: themes registered (sqlrooms-*, json themes)
  ME->>Monaco: setTheme(activeTheme) (guarded by lastDefinedForDarkMode)
  App->>ME: props update (isDark / monacoTheme / language)
  ME->>DOM: re-read CSS variables via getCssColor
  ME->>Monaco: re-run defineMonacoThemes + setTheme (if needed)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nibble vars from DOM so bright,
I stitch the themes both dark and light.
I keep a ref, I note the mode,
Then paint the editor down the road. 🎨✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title refers to a real aspect of the changes (refactoring CSS color resolution logic), but does not capture the main point of the PR, which is fixing theme color resolution issues by preventing redundant theme redefinitions in MonacoEditor. Consider a more descriptive title that reflects the primary fix: 'fix: prevent redundant Monaco theme redefinitions' or 'fix: resolve theme color resolution by defining themes once in MonacoEditor'.
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/color-utils-getCssColorFromThemeMode

Important

Action Needed: IP Allowlist Update

If your organization protects your Git platform with IP whitelisting, please add the new CodeRabbit IP address to your allowlist:

  • ✨ 136.113.208.247/32 (new)
  • 34.170.211.100/32
  • 35.222.179.152/32

Failure to add the new IP will result in interrupted reviews.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/monaco-editor/src/utils/color-utils.ts (1)

127-283: Reduce duplicate mappings in getMenuColors.
The dark/light branches are identical now that values come from CSS vars; building the map once will avoid drift.

♻️ Suggested refactor
-  if (isDarkTheme) {
-    // Dark theme mappings
-    result['editorWidget.background'] = getCssColor(
-      '--popover',
-      defaults['editorWidget.background'],
-    );
-    result['editorWidget.foreground'] = getCssColor(
-      '--popover-foreground',
-      defaults['editorWidget.foreground'],
-    );
-    result['editorWidget.border'] = getCssColor(
-      '--border',
-      defaults['editorWidget.border'],
-    );
-    result['editorSuggestWidget.background'] = getCssColor(
-      '--popover',
-      defaults['editorSuggestWidget.background'],
-    );
-    result['list.hoverBackground'] = getCssColor(
-      '--accent',
-      defaults['list.hoverBackground'],
-    );
-    result['list.highlightForeground'] = getCssColor(
-      '--primary',
-      defaults['list.highlightForeground'],
-    );
-    result['menu.background'] = getCssColor(
-      '--popover',
-      defaults['menu.background'],
-    );
-    result['menu.foreground'] = getCssColor(
-      '--popover-foreground',
-      defaults['menu.foreground'],
-    );
-    result['menu.selectionBackground'] = getCssColor(
-      '--accent',
-      defaults['menu.selectionBackground'],
-    );
-    result['menu.selectionForeground'] = getCssColor(
-      '--accent-foreground',
-      defaults['menu.selectionForeground'],
-    );
-    result['quickInput.background'] = getCssColor(
-      '--popover',
-      defaults['quickInput.background'],
-    );
-    result['quickInput.foreground'] = getCssColor(
-      '--popover-foreground',
-      defaults['quickInput.foreground'],
-    );
-    result['dropdown.background'] = getCssColor(
-      '--popover',
-      defaults['dropdown.background'],
-    );
-    result['dropdown.foreground'] = getCssColor(
-      '--popover-foreground',
-      defaults['dropdown.foreground'],
-    );
-  } else {
-    // Light theme mappings
-    result['editorWidget.background'] = getCssColor(
-      '--popover',
-      defaults['editorWidget.background'],
-    );
-    result['editorWidget.foreground'] = getCssColor(
-      '--popover-foreground',
-      defaults['editorWidget.foreground'],
-    );
-    result['editorWidget.border'] = getCssColor(
-      '--border',
-      defaults['editorWidget.border'],
-    );
-    result['editorSuggestWidget.background'] = getCssColor(
-      '--popover',
-      defaults['editorSuggestWidget.background'],
-    );
-    result['list.hoverBackground'] = getCssColor(
-      '--accent',
-      defaults['list.hoverBackground'],
-    );
-    result['list.highlightForeground'] = getCssColor(
-      '--primary',
-      defaults['list.highlightForeground'],
-    );
-    result['menu.background'] = getCssColor(
-      '--popover',
-      defaults['menu.background'],
-    );
-    result['menu.foreground'] = getCssColor(
-      '--popover-foreground',
-      defaults['menu.foreground'],
-    );
-    result['menu.selectionBackground'] = getCssColor(
-      '--accent',
-      defaults['menu.selectionBackground'],
-    );
-    result['menu.selectionForeground'] = getCssColor(
-      '--accent-foreground',
-      defaults['menu.selectionForeground'],
-    );
-    result['quickInput.background'] = getCssColor(
-      '--popover',
-      defaults['quickInput.background'],
-    );
-    result['quickInput.foreground'] = getCssColor(
-      '--popover-foreground',
-      defaults['quickInput.foreground'],
-    );
-    result['dropdown.background'] = getCssColor(
-      '--popover',
-      defaults['dropdown.background'],
-    );
-    result['dropdown.foreground'] = getCssColor(
-      '--popover-foreground',
-      defaults['dropdown.foreground'],
-    );
-  }
+  Object.assign(result, {
+    'editorWidget.background': getCssColor(
+      '--popover',
+      defaults['editorWidget.background'],
+    ),
+    'editorWidget.foreground': getCssColor(
+      '--popover-foreground',
+      defaults['editorWidget.foreground'],
+    ),
+    'editorWidget.border': getCssColor('--border', defaults['editorWidget.border']),
+    'editorSuggestWidget.background': getCssColor(
+      '--popover',
+      defaults['editorSuggestWidget.background'],
+    ),
+    'list.hoverBackground': getCssColor('--accent', defaults['list.hoverBackground']),
+    'list.highlightForeground': getCssColor(
+      '--primary',
+      defaults['list.highlightForeground'],
+    ),
+    'menu.background': getCssColor('--popover', defaults['menu.background']),
+    'menu.foreground': getCssColor('--popover-foreground', defaults['menu.foreground']),
+    'menu.selectionBackground': getCssColor(
+      '--accent',
+      defaults['menu.selectionBackground'],
+    ),
+    'menu.selectionForeground': getCssColor(
+      '--accent-foreground',
+      defaults['menu.selectionForeground'],
+    ),
+    'quickInput.background': getCssColor(
+      '--popover',
+      defaults['quickInput.background'],
+    ),
+    'quickInput.foreground': getCssColor(
+      '--popover-foreground',
+      defaults['quickInput.foreground'],
+    ),
+    'dropdown.background': getCssColor('--popover', defaults['dropdown.background']),
+    'dropdown.foreground': getCssColor(
+      '--popover-foreground',
+      defaults['dropdown.foreground'],
+    ),
+  });

Comment thread packages/monaco-editor/src/components/MonacoEditor.tsx Outdated
Comment on lines 78 to 79
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was rollbacked to the version before I edited my edits for the Monaco editor flashing.

@bdjulbic

bdjulbic commented Feb 2, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

@bdjulbic, I'll review the changes in this PR.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.


let themesDefined = false;
// Module-level singleton to track theme state
let lastDefinedForDarkMode: boolean | null = null;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This guard was needed to prevent theme redefining every time a component was created.
Like a singleton value to keep track of property isDarkMode

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts Monaco editor theming to derive colors directly from the live DOM (via CSS variables) instead of walking stylesheets or manually simulating theme modes, aiming to fix incorrect background colors under Tailwind @layer base and keep the editor synced with the app theme.

Changes:

  • Simplified color-utils by removing stylesheet rule inspection and introducing getCssColor that reads CSS variable values from getComputedStyle(document.documentElement).
  • Updated getMenuColors and getJsonEditorTheme to use the new getCssColor and rely on the current DOM theme instead of explicit theme-mode arguments.
  • Refactored MonacoEditor theme setup to define all Monaco themes from current DOM CSS vars, track the last dark/light mode at module level, and re-define/apply themes when the app theme or editor configuration changes.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
packages/monaco-editor/src/utils/color-utils.ts Reworked color resolution helpers to read live CSS variables from the DOM and simplified menu/JSON theme generation APIs to depend on current theme state.
packages/monaco-editor/src/components/MonacoEditor.tsx Refactored theme definition logic to use the new color utilities, cache last dark/light mode, and re-apply Monaco themes when relevant props or app theme change.
Comments suppressed due to low confidence (1)

packages/monaco-editor/src/utils/color-utils.ts:103

  • The PR description says a recursive search via getRawCssVarFromStylesheets() was added to fix colors inside @layer base, but in this file that function is removed and the implementation now relies solely on getComputedStyle(document.documentElement) via getCssColor. Please either update the PR description to match this approach or reintroduce and use the recursive stylesheet walk if that behavior is still intended, so future readers aren’t misled about how theme colors are actually resolved.
export function getCssColor(
  variableName: string,
  fallbackColor: string,
): string {
  if (typeof document === 'undefined') return fallbackColor;
  try {
    // Get CSS variable value from current DOM
    const cssValue = getComputedStyle(document.documentElement)
      .getPropertyValue(variableName)
      .trim();

    if (!cssValue) return fallbackColor;
    return normalizeCssColorValue(cssValue, fallbackColor);
  } catch (error) {
    console.error(`Error getting CSS variable ${variableName}:`, error);
    return fallbackColor;
  }
}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@bdjulbic
bdjulbic merged commit caa4db9 into main Feb 3, 2026
4 checks passed
@bdjulbic
bdjulbic deleted the fix/color-utils-getCssColorFromThemeMode branch February 3, 2026 17:07
@coderabbitai coderabbitai Bot mentioned this pull request Mar 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants