Releases: NSNet21/css-bridge
v1.3.0 — CSS variable jump
CSS Bridge v1.3.0 — CSS variable jump
F12 and Ctrl+Click now navigate between var(--foo) calls and --foo: definitions, with multi-theme disambiguation, hover preview, and full reverse-lookup.
What's new
CSS variable jump (#2)
- Forward jump —
F12/Ctrl+Clickonvar(--primary)lands on its--primary:definition. If multiple themes define the same name (:rootlight +.theme-darketc.), the QuickPick disambiguator lists all of them so you can pick the one you want. - Reverse navigation —
F12on a--primary:definition lists everyvar(--primary)site across the project. - Hover on
var(--foo)— shows every definition:selector → value · file:line. - Hover on
--foo:— summarizes how many places consume it, with the first eight sites listed inline. Shows*no usages found in scope*when the variable is orphaned (handy for dead-code detection). - Fallback & nested forms —
var(--primary, blue)andvar(--a, var(--b))resolve correctly. The fallback text isn't treated as a separate variable. - Multi-theme disambiguation reuses the existing QuickPick UI; selector path and var path live side-by-side without conflict.
Diagnose
CSS Bridge: Diagnose now reports per-file Var defs / Var uses counts plus the cursor-detected variable with its forward/reverse target list — so you can verify scope and lookup without having to F12 manually.
Internals
- New
parseVars(filePath)insrc/parsers/cssParser.ts:- Definitions via postcss
walkDecls(/^--/)so the parent rule's selector (:root/.theme-dark) is captured for theming context. - Usages via regex over comment-stripped content; comments are replaced with same-length whitespace so absolute offsets stay accurate.
- Cached separately from
parseSelectors(mtime-keyed, independent map) — keeps the v1.0–v1.2 selector path completely untouched.
- Definitions via postcss
- New CSS-only
CssBridgeCssHoverProviderinsrc/providers/hover.ts— registered onlanguage: 'css'only; the JSX hover provider is unchanged. getCssVarAtCursorinsrc/providers/definition.tsanchors detection on the--prefix so cursor anywhere from the leading-through the last name char resolves to the same range.cssWatcher.onDidChange/onDidDeletenow also invalidates the var cache.showDisambiguationPickgained apreviewMode: 'next' | 'same'option — selectors keep the existing "next-line" preview (so the rule body is shown), variables use "same-line" so the declaration itself is the visible preview.
Backward compatibility
- ✅ Untouched: all v1.0/v1.1/v1.2 features.
parseSelectorssignature unchanged.getCssTokenAtCursorunchanged. JSX hover provider unchanged. ⚠️ Refactored but invisible:cssParser.tsadds new exports + new cache map.definition.ts provideDefinitionadds a new branch — only fires when cursor is onvar()or a--def; existing logic for.foo/#barruns after and is unaffected.- 🎯 Intentional behavior change: F12 on
var(--foo)previously fell through to VS Code's default; now CSS Bridge intercepts and jumps. F12 on--foo:previously fell through; now finds usages. Hover onvar(--foo)adds CSS Bridge's tooltip alongside VS Code's color preview — they coexist without conflict.
Verified
- 13/13 cases pass on
node scripts/smokeVars.js(single :root / multi-theme / fallback / nested / block-comment / local def+use / orphan / whitespace / multi-line / kebab-case / @media wrap) - Part A fixture tests N1-N13 ✅ (incl. multi-theme QuickPick + Esc cancel + tooltip rendering + orphan empty-state + cache invalidation on save)
- Part B regression R1-R9 ✅ (className jump, dynamic className 15 attr-expr, hover multi-match, reverse-nav, atomic rename
totalEdits=2, JSX/CSS autocomplete, Code ActionCreate rule)
Lessons learned
- Nested CSS block comments don't work — writing the literal
*/sequence inside a/* ... */description silently breaks postcss parsing. Caught the bug in our own fixture mid-test (defs=0, uses=12 with one false-positive). Same-length whitespace replacement preserves offsets when stripping comments. showDisambiguationPickpreviews the line below by design (selectors land on.foo {and the body is the meaningful preview). For variables the location is the declaration line, so the off-by-one preview showed the next line. AddedpreviewModeoption to handle both.globFiles(scope)carries scope-isolation for free — the same function powers selector reverse-nav (verified 32-package monorepo in v1.2). Var jump inherits boundary detection without any new logic.
How to install
- VSIX: download
css-bridge-1.3.0.vsixfrom this release and install viaExtensions → ... → Install from VSIX... - Or via Marketplace:
nsnet.css-bridge(will publish shortly)
🤖 Generated with Claude Code
v1.2.0 — Dynamic className + clsx/classnames helpers
What's New
#10 Dynamic className expressions — F12 / Hover / Rename / Reverse-nav now work inside className={...}. Recognised shapes: template literals (`btn ${active ? 'is-active' : ''}`), conditionals, && / || / ?? short-circuits, string concatenation, arrays, and objects nested inside.
#4 clsx / classnames / cn / cx / twMerge helpers — string-literal arguments (and object keys like { 'btn-active': flag }) are scanned alongside className="...". Custom helper names extend the list via the new setting.
New setting
cssBridge.classNameHelpers— array of function names treated as className helpers. Default:["clsx", "classnames", "cn", "cx", "twMerge"]. Add your own (e.g.cva, project-specific helpers).
Performance
- Pre-warm parse on file open so the first F12 inside
className={...}doesn't pay the inline parse cost - 80 ms parse throttle for fast typing inside expressions
- CodeAction lightbulb skips the AST fallback to keep typing snappy on big files
Internals
- New AST-based class index module — single
@babel/parserwalk per file, mtime + document-version cached, replaces the per-feature regex scanners. Keystroke fast-path on plainclassName="..."preserved (no parse cost). - Diagnose command now reports class-index counts (
attr-string/attr-expr/helper) and the source label of the cursor token, so you can verify dynamic detection without speculation. CSS-side diagnose also surfacesDetected selector+JSX usagescount.
Trade-off (intentional)
Ctrl+. "Create rule" Quick Fix now fires only on plain className="..." — not on dynamic {...} or clsx(...) arguments. Rationale: dynamic class names are typically intentional logic (e.g. isActive && 'btn-active') rather than typos. Keeps the lightbulb noise-free on big files.
Verified
- AST walker shape smoke tests 14/14
- Stress fixture (677 lines, 1141 tokens, 540 className occurrences across 9 dynamic shapes × 60 blocks) — rename roundtrip 309 edits, reverse-nav 308 locations instant
- Real 32-package monorepo workspace — scope-isolated rename (no leak across sub-projects)
- All v1.0.x / v1.1.x regression tests pass
Install
Download the .vsix below, then:
code --install-extension css-bridge-1.2.0.vsix
Or grab from the Marketplace.
v1.1.1 — verbose polish + README docs
Polish
- Toggling
cssBridge.verboseLoggingon now surfaces the output channel automatically. Previously the channel was silently writing log entries but stayed hidden until you ranCSS Bridge: Show Output Log— confusing if you'd just flipped the setting expecting to see logs.
Docs
- README updated with the v1.1.0 features (Hover Preview, Workspace CSS Union, Aliased imports), 3 new settings, and a Commands reference table.
Install
Download `css-bridge-1.1.1.vsix` below and install via:
```
code --install-extension css-bridge-1.1.1.vsix
```
🤖 Generated with Claude Code
v1.1.0 — Workspace CSS Union, Aliased imports, Hover, Diagnose
✨ New features
- Workspace CSS Union — child components now see CSS imported by ancestors. Common case:
App.tsximportsglobals.css, child component usesclassName="container"without re-importing. F12 / Hover / Autocomplete / Code Action all work across the project. Toggle viacssBridge.includeWorkspaceCss(defaulttrue). - Aliased imports —
import '@/styles/globals.css'(or any path alias) now resolves throughtsconfig.json/jsconfig.jsoncompilerOptions.paths. - Hover preview — hover any
className/idto see the matching CSS rule body without leaving the editor. Multi-match preview shows every source. - Better project detection — recognizes Vite / Next / Remix / Rsbuild / Webpack monorepos where
reactis hoisted by workspaces. Replaces the v1.0.x package.json-only boundary check.
🛠️ Diagnose tooling
CSS Bridge: Show Output Log— open the extension's output channel.CSS Bridge: Diagnose— dump scope detection, resolved imports, alias config, workspace CSS pool, and cursor context to the output channel. Paste it when reporting bugs to short-circuit speculation.- Auto-diagnose on editor change — opt-in via
cssBridge.autoDiagnoseOnEditorChange. Lightweight per-file context dump (~5ms) on tab switch. - Verbose logging — opt-in via
cssBridge.verboseLogging. Logs every provider call (Hover, Definition, Completion, Rename, CodeAction) for live debugging.
🐛 Fixes (caught via diagnose during dogfooding)
- Tsconfig JSONC parser was greedy-matching
/*in\"@/*\"through*/in\"src/**/*\", wipingcompilerOptions. Replaced with plain JSON.parse first + string-aware fallback. stripCommentshad the same bug class for JSX —/*in a string literal (e.g.'@styles/*') through*/of a JSX comment blanked the whole className line, breaking F12/Hover/CodeAction. Replaced with a string-aware character scanner.
📦 Install
Download css-bridge-1.1.0.vsix below and install via:
```
code --install-extension css-bridge-1.1.0.vsix
```
or from VS Code: Extensions panel → `…` → Install from VSIX.
🤖 Generated with Claude Code
v1.0.1 — bug fixes
Fixes
data-id/aria-id/*-id/*ClassName=no longer falsely matched asid=/className=. Affects Jump, Peek, Autocomplete, and Rename.- Reverse navigation (CSS → JSX) and Rename no longer match attribute-shaped text inside JS/JSX comments.
- CSS-side autocomplete on
#now returns id suggestions correctly. Items keep their./#prefix on accept.
New
Ctrl+K Ctrl+P(Peek) now also works from a CSS file — peeks JSX usages of the selector under the cursor.
Perf
- Cache JSX/TSX import resolution by mtime — no more re-parsing with Babel on every cursor move.
Install
Download css-bridge-1.0.1.vsix below and install via:
```
code --install-extension css-bridge-1.0.1.vsix
```
or from VS Code: Extensions panel → … → Install from VSIX.
🤖 Generated with Claude Code
CSS Bridge v1.0.0
Initial release.
Features
- Jump & Peek — F12 / Ctrl+K Ctrl+P on className/id → CSS rule
- Reverse Navigation — F12 on CSS selector → JSX/TSX usages
- Auto-create — Ctrl+. to create missing rule or CSS file + import
- Autocomplete — className suggestions from imported CSS, and vice versa
- Project-wide Rename — Alt+R / F2 scoped to nearest package.json
Install
Download \css-bridge-1.0.0.vsix\ and run:
\
code --install-extension css-bridge-1.0.0.vsix
\
Or install directly from VS Code Marketplace.