From f712ca1440c4c4405cc3b446cc1c3417baec5686 Mon Sep 17 00:00:00 2001 From: 0-don Date: Sun, 17 May 2026 17:09:07 +0200 Subject: [PATCH] feat(css): make theme tokens + dark variant Shadow-DOM friendly Consumers that embed Studio inside an open Shadow Root - e.g. as a local-DB inspector in a host app where Tailwind's preflight would otherwise leak globally - currently lose theme tokens and dark-mode styling. The root cause is that none of these selectors cross the shadow boundary: - `:root { ... }` matches Document.documentElement only. - `.dark ` (legacy class) requires `.dark` on an ancestor in the same tree; the shadow host is outside the shadow tree. - Tailwind v4 `@custom-variant dark (&:is(.dark *))` compiles every `dark:` utility into `.dark\:foo:is(.dark *)`, same problem. This adds `:host` / `:host(.dark)` alongside the existing selectors: - `:root, :host { ... }` for theme-token blocks - `.dark, :host(.dark) { ... }` for the dark-mode block + descendant rules (`globals.css`, `prompt-plugin.css`, and the table-cell CSS module via `:global(:host(.dark))`). - `@custom-variant dark (&:where(.dark *, :host(.dark) *))` so every Tailwind `dark:` utility activates in either DOM topology. All changes are purely additive: `:host(...)` selectors don't match anything inside a normal Document, so non-shadow consumers are unaffected. Shadow-DOM consumers can now drop the runtime stylesheet rewrites that some downstream apps are currently doing to work around this (e.g. https://github.com/outerbase/studio/issues/505). --- src/app/globals.css | 28 +++++++++++++++---- src/components/editor/prompt-plugin.css | 9 ++++-- .../gui/table-cell/styles.module.css | 3 +- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index 51baefe4..3abca30f 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,7 +1,16 @@ @import "tailwindcss"; @import "./styles/markdown.css"; -@custom-variant dark (&:is(.dark *)); +/* + * `dark:` Tailwind variant. The default `&:is(.dark *)` matches an element + * inside a `.dark` ancestor in the same DOM tree. That breaks for consumers + * that mount Studio inside an open Shadow Root (e.g. to keep Tailwind's + * preflight from leaking into a host app), because descendant combinators + * can't cross the shadow boundary - the `.dark` class lives on the shadow + * host, which is outside the shadow tree. Add `:host(.dark) *` so the + * variant also matches when `.dark` is on the host element. + */ +@custom-variant dark (&:where(.dark *, :host(.dark) *)); @custom-variant interactive (&:where(.interactive, .interactive *)); @custom-variant toggle (&:where(.toggle, .toggle *)); @custom-variant square (&:where(.square, .square *)); @@ -225,7 +234,10 @@ overscroll-behavior-x: none; } - :root { + /* `:host` is added so the same tokens reach consumers that mount Studio + inside a Shadow Root; `:root` matches Document.documentElement only. */ + :root, + :host { --color-table-grid: #eee; --color-table-change: #f6e58d; @@ -244,7 +256,8 @@ } @layer base { - :root { + :root, + :host { --background: #fff; --foreground: #444; @@ -283,7 +296,8 @@ --scroll-bar-hover: #ccc; } - .dark { + .dark, + :host(.dark) { --background: #0a0a0a; --foreground: #aaa; @@ -361,7 +375,8 @@ /* FROM ORBIT DESIGN SYSTEM */ -.dark { +.dark, +:host(.dark) { /* Component colors */ /* Base colors */ @@ -527,7 +542,8 @@ outline: none !important; } -.dark .cm-table-name { +.dark .cm-table-name, +:host(.dark) .cm-table-name { color: #fd79a8; } diff --git a/src/components/editor/prompt-plugin.css b/src/components/editor/prompt-plugin.css index 702b0f89..5e9aa0bd 100644 --- a/src/components/editor/prompt-plugin.css +++ b/src/components/editor/prompt-plugin.css @@ -6,7 +6,8 @@ background: #f5f5f5; } -.dark .prompt-line-selected { +.dark .prompt-line-selected, +:host(.dark) .prompt-line-selected { background: #222; } @@ -14,7 +15,8 @@ background-color: #fab1a0 !important; } -.dark .cm-deletedChunk { +.dark .cm-deletedChunk, +:host(.dark) .cm-deletedChunk { background-color: #b54b4b !important; } @@ -26,7 +28,8 @@ background-color: #55efc4 !important; } -.dark .cm-changedLine { +.dark .cm-changedLine, +:host(.dark) .cm-changedLine { background-color: #2f6542 !important; } diff --git a/src/components/gui/table-cell/styles.module.css b/src/components/gui/table-cell/styles.module.css index 7bf2808a..2e17bdda 100644 --- a/src/components/gui/table-cell/styles.module.css +++ b/src/components/gui/table-cell/styles.module.css @@ -8,7 +8,8 @@ border: 1px solid #e00; } -:global(.dark) .change { +:global(.dark) .change, +:global(:host(.dark)) .change { @apply bg-yellow-500; }