Format : Keep a Changelog — versionning SemVer.
- Copy a token's resolved value with modifier + click : holding
⌘/Ctrl + Shiftand clicking a token reference in the editor (var(--…),$var,'{a.b}',dt('a.b'), runtime property access) opens a dropdown to copy its value. Resolution follows the full alias chain to the primitive, so a semantic alias copies the real value (#e5e9eb), not the intermediate token. The dropdown preselects the resolved value (Enter to copy), and also offers the token reference as written in code. A transient📋 Copied "…"balloon confirms the copy. Implemented as a programmaticEditorMouseListener(CopyValueClickStartup) that consumes the click so the IDE doesn't reposition the caret or start a multi-caret selection. Closes #27. - Colour notation conversions in the copy dropdown : for
COLORtokens the dropdown surfaces the resolved colour inHEX,RGB,HSLandOKLCH, skipping whichever notation the resolved value already uses. OKLCH is computed via Björn Ottosson's sRGB → OKLab transform (ColorConversions), and all numeric output is formatted withLocale.ROOTso the decimal separator is always.regardless of the IDE locale. - Configurable copy shortcut : a new Copy value (modifier + click) section under Settings → Tools → Token Flow → Triggers lets the user pick the modifier combo (
⌘/Ctrl + Shift,Ctrl + Shift,Ctrl + Alt,Alt + Shift,Alt) or disable the gesture. The⌘/Ctrl + Shiftdefault maps to the platform's primary modifier (⌘ on macOS, Ctrl elsewhere).
ColorConversionsTestlocks the HEX/RGB/HSL/OKLCH conversions, the source-format detection, and the locale-safe decimal separator.
- TS/JS indexer — value-based object & leaf filtering : each exported object is now classified by the shape of its leaf values. An object is kept only when its values are recognisable style primitives (colours, dimensions, aliases, unitless numbers, style keywords). Objects holding arbitrary application strings — event-name enums (
{ CREATED: 'ENTITY_CREATED' }), config maps, JSON-Schema bodies (type: 'object',minimum: 0) — are dropped wholesale. Within a kept object, individual non-style leaves are also dropped: a status-config map ({ PICKING: { label: 'En picking', variant: 'info', bg: '#e8ecf5', color: '#4563a0' } }) now indexes only the colours, no longer thelabel/variantstrings. Closes #24. - TS/JS indexer — JSON Schema files skipped : files containing JSON Schema vocabulary keys (
$schema,$defs,$ref) — quoted or unquoted — are classifiedMode.NONEand bypass the parser entirely. Schema paths ($defs.WidgetSlot.properties.flex.minimum) and$refstrings ('#/$defs/LayoutRow') no longer appear as pseudo-tokens. - TS/JS indexer — Storybook / test files skipped : files matching
*.stories.*,*.spec.*,*.test.*or importing from@storybook/*are excluded before parsing. - SCSS indexer — local variables skipped :
$variablesdeclared inside any block (@function,@mixin,@each, selector…) are recognised as local Sass helpers and no longer indexed. Only brace-depth-0 declarations are treated as tokens. - SCSS / CSS indexer — BEM modifiers no longer captured as variables : the
--namesegment of a BEM selector was being captured by the custom-property regex, producing fake tokens (--closeable: hover,--selected: not(...)). The negative lookbehind now also excludes the SCSS parent-ref form&--selected:not(.x), and a value containing{(a captured selector) is rejected outright.--is only treated as a token in a real property declaration or avar(--…)call. Closes #25. - Suggestion engine — no circular self-reference : a token definition flagged as hardcoded no longer suggests itself as the replacement.
--color-bg-page: #e5e9ebused to offervar(--color-bg-page)(which would produce--color-bg-page: var(--color-bg-page)); the engine now excludes the token currently being declared from its own suggestion list, across CSS (--x), SCSS ($x) and JS object-path (colors.bg) declarations. Closes #23.
- Analyser — "Active editor" scope option removed : the Scope picker in the Analyser toolbar no longer carries an Active editor (…) entry, and the panel no longer follows the active editor. The analysed scope is now a purely explicit, user-driven choice (All project by default, plus every configured scope), which keeps the report stable as you navigate between files. The Library and Hardcoded Values panels keep their active-editor follow-along behaviour unchanged. Closes #21.
- Unit-test suites :
StyleValueHeuristicsTestandJsParserFalsePositiveTestcover the value classifier and the three false-positive families from #24.CssVarRegexTestlocks the BEM-safe behaviour from #25.SuggestionEngineSelfReferenceTestlocks the no-self-reference behaviour from #23.
- Analyser — sticky section headers : while scrolling through a long report, the header of the section currently in view pins itself at the top of the panel. The sticky strip mirrors the section title and count — you always know which section you are reading without scrolling back to the heading.
- Analyser — section order : Broken references is now the first section — these are genuine bugs (broken
var(--…)/$varreferences) and should be triaged before the lower-urgency hardcoded sections. Hardcoded clusters and Hardcoded values follow immediately after. - Analyser — occurrence rows show
filename:line · propertyinstead of parent folder : the per-file list inside an expanded hardcoded row now shows the CSS/JS property the literal is bound to (Button.scss:42 · padding) instead of echoing the parent directory name. The fixed 28 px height cap that clipped long labels has been removed. - Analyser — no more 50-row ceiling on hardcoded results : the hard cap of 50 at the analyser layer has been removed. Truncation is now handled exclusively by the
+ N more…expander in the UI, so the count badge always matches the real number of detected items.
- Analyser — token definitions no longer flagged as hardcoded : literal values that are part of a token declaration (SCSS
$var: value, CSS--var: value, JSON / JS object entries such as"sm": "8px") are now correctly recognised as definitions and excluded from both Hardcoded clusters and Hardcoded values. Declaration detection has been extended to quoted JSON / JS object keys ("borderRadius": "8px","sm": 8). - Analyser — pure token-catalog files fully excluded from hardcoded scan :
.ts/.tsx/.js/.jsx/.jsonfiles registered as token sources are now skipped entirely in the hardcoded scan, eliminating false positives from design-token catalog files. - Analyser — TS / JS files only receive format-compatible token suggestions : CSS custom-property suggestions (
var(--…)) are no longer offered when the occurrence lives in a.ts/.tsx/.js/.jsxsource. Only JS-reachable token kinds (object-path, runtime property access, helper call) are surfaced.
- Analyser — hardcoded results split into clusters + values : the legacy "Hardcoded clusters" section is now two sections. Hardcoded clusters keeps the original semantic — repeated literals with no matching token in the active scope (design opportunities). Hardcoded values is new — literals where one or more tokens already exist for the same
(value, category)pair (actionable technical debt). Values are grouped by(literal + property family)so the same value used under two distinct properties (12px paddingvs12px font-size) shows up as two separate rows with their own role-aware suggestion fromSuggestionEngine. The previous singleHARDCODED_PRESSUREscore axis is replaced byHARDCODED_OPPORTUNITY(weight 15, one-to-one per hit) andHARDCODED_DEBT(weight 10, x2 penalty per hit — the fix is immediate). Closes #19. - Analyser — ambiguous-token detection : new informational section surfaces tokens whose name plausibly maps to more than one value family — typography-leaning words holding a colour (
--text-default: #45566),--icon-*holding a raw length, pure role/slot names with no category hint (--primary,--default). Each row carries areasonexplaining the ambiguity and analternativeInterpretationdescribing the second plausible reading. Surfaced as suggestions, never as errors. - Alt+T on a contextually-declared CSS variable lists its declaration sites : when the caret sits on a
var(--c)whose--cis declared outside the registered token sources (consumer override, Angular host binding, React/Vue inline style, vanillasetPropertycall), Alt+T now surfaces a navigable list of every declaration site instead of the historical "No alternatives found." message. Each row shows the innermost CSS selector (<runtime>for runtime injection), the raw value as written, the project-relative file path and 1-based line number, and a colour swatch when the value parses as a colour (ColorParser). Clicking a row opens the file at the exact offset viaOpenFileDescriptor. Static CSS declarations are listed before runtime occurrences so the most actionable sites (concrete values) come first. The popup honoursJBPopupFactory.createPopupChooserBuildersemantics — type-to-filter by selector / value / path, arrow keys to move, Enter to jump, Esc to dismiss. DynamicCssVarIndexnow stores full occurrences : the project-wide index introduced in 0.1.9 was reshaped fromSet<String>toMap<String, List<CssVarOccurrence>>. EachCssVarOccurrencecarries the variable name, raw value, file path, byte offset, 1-based line, innermost selector (CSS only) and aisRuntimeflag. Broken-ref detection still reads thekeysview viaget()so the 0.1.9 callers are untouched — no behaviour change there. Innermost selector is best-effort : a backwards walk over balanced{}from the declaration offset, returningnullfor top-level declarations / malformed input / Sass indent files. Nested SCSS rules return the innermost selector only — walking the full parent chain would require a real parser, and the innermost is enough to identify the declaration at a glance.- Pre-warmed lookup :
TokenAlternativesShower.shownow readsoccurrencesOf(name)inside its existingTask.Backgroundable, so the EDT branch that displays the popup never pays the first-walk cost. The lookup is no-op when the hit's name doesn't start with--.
- Sharper suggestion engine — family-aware filtering :
SuggestionEngine.findSuggestionsnow drops exact matches whoseTokenCategoryis semantically incompatible with the expected one before ranking.SPACING / SIZING / RADIUSremain interchangeable (the metric group — common DS practice).TYPOGRAPHYandBORDERstand alone — a typography token can no longer surface on awidth:20pxjust because no sizing token holds that exact value.score()also applies a heavy cross-family penalty as a defense in depth. - Sharper suggestion engine — name-based filtering : on top of category filtering, a defense-in-depth name check rejects any token whose name contains a typography-leaning segment (
typography,font,text,weight,leading,letter,family,tracking,kerning,decoration,title,heading,caption,paragraph) when the surrounding property expects a metric value (SPACING / SIZING / RADIUS / BORDER / LAYOUT). Catches the canonical pitfall where a--size-typography-title-md: 20pxtoken is wrongly categorised as SIZING by itssize-prefix and would otherwise surface onwidth: 20px. Word-boundary lookaround keeps generic metric names (--size-md) unaffected. - Sharper suggestion engine — dot-path tier classification :
SuggestionEngine.tierOfandroleOfnow split the leading segment on both-and., so JS object-path token names (units.sm,palette.blue.500) are classified the same as their dash-separated equivalents (units-sm). Primitives in JS-object DSes are now correctly outranked by semantic alternatives at identical values.
- Analyser scope selector no longer drifts on file switch : the Scope picker in the Analyser toolbar used to auto-resolve to the deepest scope of the active editor on every editor selection change. It now behaves as a sticky user-controlled setting — explicit picks are remembered across editor changes, settings rebuilds and "Active editor (…)" label refreshes. The
LibraryandHardcoded Valuespanels keep their existing active-editor follow-along behaviour unchanged.
- CSS variables declared outside token sources are no longer flagged as broken : Token Flow now recognises any
--namedeclared anywhere in the codebase, not just in files registered as token sources. A new project-levelDynamicCssVarIndexservice walks.ts/.tsx/.js/.jsx/.html/.vue/.css/.scss/.sassonce and caches the result against the IDE's PSI modification tracker — subsequent reads are free until the user edits something. Two families are detected :- Runtime injection by component code — Angular host bindings (
[style.--var],[attr.style.--var]), Angular template property syntax (style.--var="…"), DOMelement.style.setProperty('--var', …)calls (single / double / back-tick quotes), React inline styles (<div style={{ '--var': value }}>), Vue:styleshorthand. - Contextual CSS overrides — the CSS Custom Property API pattern where a generic component reads
var(--c, fallback)and consumer components set--clocally in their own stylesheets. Any bare--name: valuedeclaration inside a rule body counts (:root, host selectors, BEM-style consumer selectors, …). BEM identifiers like.block__elem--mod:hoverare correctly ignored thanks to a negative lookbehind on alphanumerics. Both the Analyser (broken references / reference-integrity score) and the Hardcoded Values panel honour the index. A fallback expression alone (var(--x, inherit)) is not enough — a variable that resolves to nothing anywhere in the project is still a broken reference. Closes #16.
- Runtime injection by component code — Angular host bindings (
- New setting : Settings → Token Flow → Analyser → "Recognise CSS variables declared outside token sources (runtime injection + contextual CSS rules)". On by default; uncheck to fall back to the pre-0.1.9 strict behaviour where every reference must point at a declaration inside a registered token source.
- External token prefixes per scope : new External tab in Settings → Token Flow → Scopes that lets you list CSS custom-property prefixes injected at runtime by an external framework (PrimeNG
--p-, Ionic--ion-, Angular Material--mat-, Material Web--mdc-, Vuetify--v-, Bootstrap--bs-, Radix--radix-, Quasar--q-, Element Plus--el-, Mantine--mantine-, Carbon--cds-, …). References matching one of these prefixes are treated as known-external and never flagged as broken in the Analyser or the Hardcoded Values panel. Closes #15. - Auto-detect external prefixes from
package.json: the External tab gains an Auto-detect from package.json… link that scans the project tree (up to 12package.jsonfiles, skippingnode_modules/.git/build outputs), maps known dependencies to their CSS-var prefix and adds them to the current scope in one click. A summary popup lists what was added vs. already-present. - Project-open detection notification : the first time the plugin opens a project that depends on a known UI framework but has no
externalPrefixesconfigured, a balloon offers three actions — Add to all scopes (one-click acceptance, creates a Common scope if none exists), Configure… (opens Settings), Don't show again (silences the prompt forever). The "notified" state is persisted per-project so the user is never nagged twice. - JSON config schema v2 :
ScopeConfigIO.CURRENT_VERSIONis now2— exports includeexternalPrefixesper scope. Importing a v1 file still works (the field defaults to empty list). - Hardcoded Values — token-source files are skipped with an explanatory banner : when the active editor is registered as a
sourcePathsentry of any scope, the panel now shows "This file is declared as a token source — hardcoded value detection is disabled here" and bails out before scanning. No more noise on_tokens-*.scsscatalogs where every literal is by definition a token declaration. Editing the scope's sources in Settings → Token Flow re-enables the scan if needed. - Hardcoded Values — SCSS map values are no longer flagged : literals living inside a
$name: (…)or"key": (…)SCSS map (the Style-Dictionary / theme-config pattern used by$themes-config: ("themeX": ("light": ("token": #001a70, …)))) are now recognised as token definitions and skipped. Detection is purely lexical, handles nested maps to any depth, and ignores parens / colons that live inside strings or comments. Works in files that aren't formally declared as token sources too, so mixed files (style + inline map) are handled cleanly. - Hardcoded Values — search & property filter : the panel gains a search field (above the rows) that filters by literal, selector, surrounding CSS property and any suggested token's name / resolved value (multi-term, AND, case-insensitive). A new filter button (round, next to the search field) opens a popup listing every CSS property detected in the current scan, grouped by category (
Spacing,Sizing,Typography,Color,Radius,Shadow,Border,Effects,Duration,Layout,Z-index,Opacity,Icon,Other), with a per-property count. A nested search field inside the popup narrows the property checklist as you type and hides group headers that no longer have a visible row. A Reset button clears everything (property excludes + hide-unmatched). - Filter popup — "Hide rows without a token suggestion" checkbox : the toolbar toggle moved into the new filter popup so every view-narrowing control lives in the same place. Broken references stay visible even when the option is on — they're actionable.
- Suggestion engine — token tier awareness : tokens are now classified as primitive (
units-,palette-,base-,primitive-,core-,scale-,raw-), component (token-,comp-,component-) or semantic (everything else), and the suggestion ranker prefers semantic tokens when several candidates share the same resolved value. Fixes the long-standing case wherepadding: 32pxproposedvar(--units-xl)instead ofvar(--spacing-xl)— both being legitimately equal to32pxbut the latter being the semantic spacing token. - Suggestion engine — property-to-role matching for colors : the inspection now derives an expected role (surface / content / stroke / effect) from the CSS property at the literal's position and matches it against the token name. Tokens carrying the right role segment (
-surface-,-content-,-stroke-,-shadow-,-focus-, etc.) get a strong score boost ; tokens carrying a conflicting role are actively demoted. Sobackground: #005bffnow preferstoken-actions-high-surface-defaultover a same-value*-content-*token, andcolor: …does the opposite. Properties mapped :background[-color]/fill→ surface ;color/caret-color/accent-color/text-decoration-color→ content ;border-color/outline-color/stroke→ stroke ;box-shadow/text-shadow/outline/filter/backdrop-filter→ effect. - Suggestion engine — multi-criterion ranking :
score()was rewritten from "category match minus shortest name wins" to a weighted combination of (category alignment, role alignment, tier, exact-vs-fuzzy, length). Token-name length is now a last-resort tiebreaker, so a longer-but-more-semantic name can outrank a shorter primitive one — which the previous ranking made impossible. - Suggestion engine — fuzzy color tiebreaking : when no exact color match exists and the engine falls back to RGB-distance suggestions, ties at near-identical distance are now broken by the semantic score, so a
background: #006cffsurfaces a-surface-token rather than a same-distance-content-one.
- Scope configuration import / export : Settings → Token Flow → Scopes now exposes Import… and Export… links above the scope list. Export writes every configured scope (name, root, sources, whitelist, analysis excludes) to a versioned JSON file. Import reads such a file and asks whether to Replace the current list or Merge it (case-insensitive name match — existing scopes get overwritten, new ones are appended). Closes #12.
- Versioned config file : the JSON carries a
versionfield. Older plugin builds refuse files produced by a newer schema rather than silently dropping fields. Current schema version is1. - Vue Single File Components (
.vue) support : tokens declared inside<style>and<style lang="scss">blocks of a Vue SFC are now indexed, surfaced in the Library, and counted in audit coverage. Hardcoded value detection, code completion, Alt+T alternatives and Go-to-declaration all operate inside the style blocks — and stay silent in<template>/<script>to avoid corrupting the surrounding HTML / JS. Implementation is text-based (no dependency on the Vue plugin), so it works identically in Community and Ultimate. Multiple<style>blocks per SFC are supported;<style scoped>and<style module>behave the same.<style src="…">blocks defer to the regular extension-based walker on the referenced file. Closes #3. - Library family / sub-family grouping : inside each big category accordion (Color, Spacing, …), the Library can now insert a two-level hierarchy of headers — family (e.g.
HIGH,LOW,PRIMARY) and sub-family (SURFACE,CONTENT,STROKE, …) — derived from the structure of token names alone. No hard-coded vocabulary: the algorithm strips the longest common prefix shared by tokens in a category, trims the trailing state segment, and buckets by what's left, so it adapts to any naming convention. Token rows indent under their header so the alignment reads like a tree, not a flat list. A new toolbar button (group-by icon next to the view-mode toggle) toggles the grouping; off by default, the preference persists per-project and lives in the panel rather than in Settings. - Sticky category header in the Library : when scrolling past a category, its header pins to the top of the viewport (with the same chevron behaviour as the in-list row) so the active context is always visible in long catalogues.
- Justified category bar : category header is now laid out as
[chevron] TITLE … (count)— title left-aligned, count badge right-aligned and tinted with the accent foreground so it no longer reads like a resolved token value.
- Variant tooltip — vertical layout : the per-variant tooltip on token rows (Library, hover popup, inspection tooltips) used to render a horizontal HTML table that blew up width-wise as soon as a token had more than 2-3 variants. Replaced with a justified one-line-per-variant layout: variant label on the left, swatch / category glyph + resolved value right-aligned, themes grouped with discrete subheaders when multiple themes are present. Same data, easier to compare side-by-side.
- Hardcoded Values — tighter row layout : rows now indent under their selector header (so the grouping reads as a small tree), the literal column is narrower (110 vs 140 px, recovers space for the suggestion combo), and the suggestion combo grows to 30 px tall so the selected value never has its descender clipped.
- Hardcoded Values — hide rows without a suggestion : a new toolbar toggle (filter icon) suppresses literals that have no matching design token; broken references stay visible because they are actionable. On by default, persisted per project. The status line reports
… · N hiddenso it's obvious the filter is shrinking the view. - Library — Token-kind filter syncs with file chips : ticking / unticking a kind in the filter popup now flips every file chip of that kind in the strip below the search bar, and vice-versa (the last muted file of a kind also unticks the kind). The two filter surfaces no longer drift.
- Library — Grid view indent under family / sub-family headers : card wraps inherit the same left padding as their heading label, with extra vertical spacing between families so blocks read as distinct sections instead of a single grid.
- Scope chip vertical alignment : in the Library and Hardcoded Values toolbars, the
Scope: [Name] (?)chip is now vertically centred against the action-toolbar buttons on its left.
- Light-theme adaptation in the Library : sub-family header foreground was previously inverted (
JBColor(light, dark)was set asJBColor(pale, dark)— illegible in both themes); category / family / sub-family palette rebuilt with proper light-vs-dark contrast steps. The resolved-value text, scope label and filter-popup section headers now use the platform's adaptive muted foreground instead of the fixedJBColor.GRAY(which isGray._128and never adapts). - Light-theme dark bands behind Library category headers :
gridContainer, the sticky header panel and the grid scroll-pane viewport now followlist.background, so the section separators no longer paint a dark band over a cream container on light themes whereJPanel.backgroundandList.backgrounddiverge.
- Multi-term library search : the Library search field now tokenises the query on spaces, dashes and underscores. Each term must match the token name or value (AND), order-insensitive — typing
informative contentfinds--token-informative-highlight-content-hover. - Stale-analysis banner : after running the Analyser, the panel watches every file referenced by the report (broken refs + token-source files). When any of them changes on disk, a yellow banner appears inviting a re-run, so fixing a broken reference no longer leaves the list stale.
- Scope reordering : up/down arrows in Settings → Token Flow → Scopes let you reorder the list. The order is reflected immediately in the Analyser scope picker.
- Analysis-exclude paths per scope : new Excludes tab in the scope detail. Folders or files added here are skipped by the Analyser (coverage, broken refs, hardcoded clusters) — useful when a wide scope root contains unrelated sub-modules.
- Library kind filter : the existing funnel popup now opens with a Token kind section above Families. Toggle CSS / SCSS / JS-JSON to slice mixed-stack catalogs without unchecking files one by one. The funnel button switches to its active state whenever any kind/family is excluded.
- Context-aware token drop & paste : dragging or pasting a JS_OBJECT_PATH token (
'{path}') into a backtick template literal in TS/JS now inserts${dt('path')}(ordt('path')when the caret is already inside${…}). Driven by a newCopyPastePostProcessorthat recognises a custom transferable shipped by the Library.
- Scope detail layout : the three lists (Sources / Whitelist / Excludes) are now grouped under a tabbed pane instead of stacked sections, removing the vertical scroll in the Settings dialog.
- Analyser toolbar : redundant Refresh and Re-sync scopes buttons removed. A single Run analysis action flips to Re-run analysis once a report exists; the new banner covers the auto-detect case the legacy buttons tried to address.
- Accordion headers : in the Analyser, the chevron and title stay left while the item count and the contextual
(?)icon are pushed to the right edge — easier to scan. - Broken-reference row : token name on line 1 (red, bold),
filename:lineon line 2 in muted grey — consistent with other Analyser rows. - Token copy/drag transferable : every Library copy or drag of a JS object-path token now ships an extra clipboard flavor so paste-side rewrapping kicks in across copy/paste, drag-and-drop, the context menu, and the card's copy button.
- Alt+T preserves the
dt(wrapper : selecting an alternative on a${dt('token.x.y')}reference no longer rewrites the call into a bare Style-Dictionary alias ('{…}') — thedt(…)shell is detected from the hit text and kept. - VFS subscription bug : the stale-analysis banner now actually fires. The previous wiring subscribed
VirtualFileManager.VFS_CHANGESon the project message bus, but it is an application-level topic and never delivered events. - Scope combo reorder reflection : the Analyser scope picker is rebuilt with an atomic
ComboBoxModelswap rather than a series ofremoveAllItems/addItemcalls, so reordering scopes in settings always reflects in the dropdown.
- Broken Reference Detection : the Analyser now lists references that don't resolve to any known token (
var(--foo),'{token.x.y}',dt('x.y')). Surfaced in both the dedicated Broken references accordion and inline in the Hardcoded Values panel (yellow warning icon, dedicated row state). - Reference Integrity score : new 5th axis in the global note (weight 20 %), heavily penalising broken references. Existing weights rebalanced (Semantic 30→20, Usage 30→25, Duplication 20→15, Hardcoded 20).
- Smart Suggestions with fallbacks : when a
var(--token, #fff)reference is broken, the suggestion engine treats the#ffffallback as a value hint and proposes matching colour tokens first. Name-similarity (Levenshtein) suggestions surface even without a fallback. - Ignored Library Files : Settings → Token Flow now accepts a list of paths to exclude (e.g. vendored design-system packages). Symbols declared inside are dropped from the analyser to keep the false-positive count down.
- CSS Named Colors detection : scanner now identifies standard CSS named colors as hardcoded values.
- Scope display in Hardcoded Values : active scope is shown in the panel toolbar.
- Dynamic list expansion : long Analyser sections now have a clickable
+x morelink.
- alt+T on JS token references :
'{token.modeLight.x.y}'anddt('token.x.y')no longer fall through to "No alternatives found".TokenNameParser.resolveReferencetolerates a leading export-binding segment (token.), a mode segment (modeLight/modeDark), and a single camelCase merge / split per path (sodefault.highmatchesdefaultHighand vice versa). Completion, goto and the broken-reference check use the same resolver. - CSS
var()inside TS template literals :var(--name)written inside a backtick string in.ts/.tsxis now recognised by alt+T. The detector used to mistakevar(...)for a JS helper call; CSS functional notations (var,calc,rgb*,hsl*, gradients, transforms…) are now excluded from helper-call detection. - Hardcoded suggestions stay in-category :
padding: 0 6pxused to suggest--shadow-md-blur: 6pxbecause the value index ignored category. The index is now keyed by(category, normalised value), with controlled fallback inside the length-bearing family (SPACING, RADIUS, SIZING, TYPOGRAPHY, BORDER). No more bleed into SHADOW, EFFECTS, DURATION, OPACITY or COLOR. - Semantic incoherences respect the categorizer :
--stroke-default: 1pxis no longer flagged. WhenTokenCategorizerhas already reconciled a name-vs-value clash (here: name hints COLOR, value is length → BORDER), the incoherence detector trusts that verdict instead of flagging on the literal name reading. - Analyser accordion spacing : collapsing every section no longer inflates the gap between headers. The width-cap wrapper now follows the child's preferred height instead of stretching vertically.
- Comments ignored in scanner : values inside code comments are no longer detected.
var(--token, fallback)fallbacks : literals inside the fallback slot are no longer reported as separate hardcoded values.- Circular token definitions : literals used inside a token's own declaration are no longer flagged.
- Levenshtein similarity : fixed an inverted
copyIntoin the suggestion engine that made name-similarity distances stale beyond the first row.
- "Non-existent tokens" → "Broken references" : matches the underlying
BrokenReferencedata class and reads as an action item rather than a category. - Deprecated IntelliJ APIs removed : migrated off
com.intellij.ui.components.labels.ActionLink(scheduled for removal), the deprecated Kotlin top-levelrunReadAction { … }(11 sites, now routed through areadAction { }helper backed byReadAction.compute), and the deprecatedgetData(dataId)override (replaced byuiDataSnapshot(sink)withsink[COPY_PROVIDER] = …). - UI harmonisation : scope info right-aligned in toolbars across panels.
- SCSS broken-reference noise :
$namereferences are excluded from the broken-reference report (compiler handles them).
- Design System Dashboard - Grid View (Cards) :
- New visual grid mode for tokens, offering a much more visual and modern alternative to the list view.
- Token Cards : Each token is represented by a card with visual previews (color circles, radius boxes, spacing indicators), action buttons (copy, info), and modern rounded aesthetics.
- Persistence : Selected view mode (List/Grid) is saved per project.
- New Token Categories : Added more precise categorization for better organization:
EFFECTS,LAYOUT,SIZING,BORDER,OPACITY, etICON.- Enriched existing categories :
COLOR,TYPOGRAPHY,SHADOW,DURATION, andSPACINGnow recognize a much wider range of semantic keywords (e.g., surface, gradient, kerning, viewport, etc.). - Strict evaluation order : Prevents collisions by ensuring composite keywords (like
border-colororbox-shadow) are correctly evaluated before their root words.
- Active Scope Awareness : Both the Dashboard Library and the Analyser tab now visibly display the current active scope, automatically adapting as you switch between different files.
- Contextual Help : Added an information
(i)button near the scope indicators, explaining how scopes work and linking directly to the plugin settings. - UI Polish : The Analyser tab now features perfectly centered empty-states and a native IntelliJ loading animation during analysis.
- Incorrect token categorization for Z-INDEX :
- Tokens are no longer classified as
Z-INDEXsolely based on having a small integer value (e.g.$breakpoint-phone: 0or--grid-columns: 4). - The categorization logic now prioritizes naming conventions, correctly identifying tokens containing
z-index,layer,depth, orelevationas Z-INDEX, while letting other integer values fall through to their correct context orOTHER.
- Tokens are no longer classified as
- Copying Tokens :
Cmd + C(orCtrl + C) and the "Copy token" context menu in the Library list view now correctly copy the token's reference expression (e.g.var(--token)) instead of internal data. - Scope Visibility Bug : Fixed an issue where the Library would appear empty when editing a file that is included via a scope's
sourcePaths.
- Gutter color swatches for SCSS variables :
- Implementation of
TokenColorProvider(IntelliJElementColorProvider) allowing SCSS variables ($color-name) to display a color preview icon in the editor gutter, consistent with native CSS custom properties. - Integration with the project's real-time
TokenIndexfor accurate visual representation of design tokens.
- Implementation of
- Handling of SCSS/CSS modifiers (
!default,!global,!important) :TokenScannernow automatically strips these flags from extracted values, preventing them from breaking color parsing and alias resolution. #2- Alias resolution now works correctly for variables using these modifiers (e.g.
$app-highlight: $app-primary !default;). #2 - Color previews now correctly render for declarations using these flags (e.g.
$app-body-fontColor: #333333 !default;). #2
- Ignorer les déclarations de variables dans l'analyse :
- Par défaut, les valeurs littérales affectées à une variable (ex:
$color: #fff) ne sont plus marquées comme "hardcoded". Cela évite de flagger la définition même de vos tokens. - Ajout d'un nouvel onglet Analyser dans les réglages pour permettre de forcer la détection si besoin.
- Par défaut, les valeurs littérales affectées à une variable (ex:
- Support React Native / CSS-in-JS runtime themes :
- Nouveau
TokenKind.JS_RUNTIME_PROPERTYpour les jetons accédés par propriété (colors.PRIMARY_500,radius.sm,theme.fontPresets.h1.fontSize). - Détection des
const X = { … }(bag, garde le préfixeX.) et desexport const X: Type = { … }(agrégateur typé, strippe le préfixe → chemins typecolors.PRIMARY_500/fontPresets.h1.fontSizealignés sur les re-exports barrel). - Résolution des alias bare-property (
PRIMARY_500: colors.PRIMARY_500) en plus des alias Style-Dictionary{…}. - Dispatch automatique par fichier (
JsTokenFileParserRegistry) : présence d'aliases'{a.b}'→ Style-Dictionary ; sinon importsreact-native/StyleSheet.create/ typed export → Runtime ; fallback historique pour les presets sans alias.
- Nouveau
- Helpers callables (
spacing,radius, …) — nouveauTokenKind.JS_RUNTIME_FUNCTION:RuntimeFunctionParserdétecte les arrow functions linéaires(p[: T]) => UNIT * p(et variantesMath.floor(unit * Math.abs(p)),UNIT * Math.abs(p), p ↔ unit swappé).UNITpeut être un littéral numérique ou uneconst NAME = NUMBERdéclarée plus haut.- Suggestions inversées : un
12pxhardcodé + un helperspacing(unit=8)proposespacing(1.5)(snap au quart de pas, tolérance 0.05). - Alt+T sur
spacing(0.5)ouvre une popup de scale (spacing(0.25),spacing(0.5),spacing(1), …) avec pré-sélection de la valeur courante. - Badge ƒ dans
TokenCellRendererpour distinguer les helpers callables des jetons à valeur fixe.
- Détection des littéraux numériques sans unité : nouveau
LiteralFinder.Kind.NUMBERqui matcheIDENT: NUMBER(ex :fontSize: 34,lineHeight: 24,opacity: 0.5). Filtré aux fichiers JS/TS dans l'inspection et le panel Hardcoded values (CSS shorthandborder: 1 solid redaurait sinon généré du bruit). Numéros à l'intérieur d'un(…)(arguments de helper) ignorés. - Re-sync action dans la toolbar de l'onglet Analyser (icône
ForceRefresh) : drop hard du cacheTokenIndex+ reconstruction du combo de scope. TokenSelectorSettings.fireScopesChanged()+addScopesChangeListener(): nouvelle API pubsub permettant aux panneaux live de réagir aux modifications de scope sans restart IDE.AnalyzePanels'y abonne pour reconstruire son combo et invalider l'analyse précédente.TokenLocatorreconnaît les expressions runtime :- Property-access chains
colors.PRIMARY_500,theme.radius.sm(requiert au moins un., rejette les contextes$/-). - Helper calls
spacing(0.5)(capture l'expression complète, rejette lesobj.method(…)).
- Property-access chains
- Complétion par préfixe runtime : trigger
colors./theme.radius.dans les.ts/.tsxpropose les jetonsJS_RUNTIME_PROPERTYcorrespondants.
- Refactor
scanner/parsers/:JsObjectTokenParserexpose désormaisparseAt(text, openBrace, initialPath)réutilisable. Les stratégiesStyleDictionaryParser,RuntimeObjectParser,RuntimeFunctionParsercohabitent derrièreJsTokenFileParserRegistry. Ajouter un nouveau stack = une seule classe à enregistrer. - Centralisation du formatage de référence : nouveau
TokenReference.expression(token)— toutes les insertions (var(--name),$name,'{path}',colors.X,spacing(N)) passent par ce helper. Ajouter un futurTokenKindn'est plus qu'une seule branche. - Popup de complétion par valeur :
setRequestFocus(false)+setCancelOnClickOutside(true)→ l'éditeur garde le focus, les frappes continuent dans le code, la popup agit comme un hint cliquable. Plus de4qui termine dans le champ de recherche au lieu du fichier. - Analyser scope-aware :
DesignSystemAnalyzer.computeCoverageacceptescopeFileet restreint le file walk auxrootPathdes scopes actifs (résolus viaScopeResolver.activeScopesFor). LessourcePathsexclus sont aussi limités aux scopes actifs (au lieu de l'union globale qui masquait des hits valides). - Annotations de type acceptées par le scanner :
export const X: Theme = { … }est désormais reconnu (la regex historique stoppait sur l'annotation).
- Quick-fixes JS/TS insèrent désormais la syntaxe correcte selon le
TokenKind('{path}'pour Style-Dictionary,colors.Xpour property-access,spacing(1.5)pour helper call). Avant, l'ajout d'un kind nécessitait de toucher 5 sites distincts ; centralisé viaTokenReference. - Cache
TokenIndexinvalidé après changement de scope : le listenerfireScopesChangedest déclenché aprèsTokenIndex.invalidate(), donc les panels live re-fetch sur un état frais.
- Hover popup — variants groupées par thème : un token déclaré dans un map SCSS imbriqué (
$themes-config -> "themeOne" -> "light" -> …) affichait ses variantes en colonnes platesdefault | dark | light | dark | light | darksans correspondance thème ↔ mode. Le scanner remonte désormais la chaîne de contexte du token primary (DeclarationContext.describeAtétendu àCSS_CUSTOM_PROPERTYetSCSS_VARIABLE, plus seulementJS_OBJECT_PATH), etparseConditionretombe sur"default"au lieu de fuiter:root/@mediaquand la chaîne ne contient que du structurel. Résultat : header à 2 lignesthemeOne | themeTwo | themeThree×light | darkpour 3 thèmes × 2 modes. - Settings — onglet Scopes scroll horizontal : les paragraphes d'intro (HTML wrappés via
JEditorPane) annonçaient unepreferredSize.widthégale à la longueur du texte non-wrappé, ce qui forçait leJScrollPanedu dialog Settings à afficher une scrollbar horizontale. Override degetPreferredSize()qui force un layout à la largeur du parent (calcul de la hauteur wrappée correcte) puis claimwidth=0→ le parent peut shrinker, BorderLayout.NORTH grant la pleine largeur au render → wrapping HTML honoré.
- Marketplace metadata : vendor email mis à jour (
robinlopez.contact@gmail.com), description CDATA simplifiée (suppression de la version FR doublonnée et de la cover image inline — déjà visible dans le README et sur la page Marketplace).
Note : entrées listées initialement dans
[Unreleased]lors du développement avant la première release publique. Conservées pour traçabilité.
- Support TS/JS preset files (PrimeUIX, Style Dictionary, Material 3 themes…) :
- Nouvelles extensions scannées :
.ts/.tsx/.js/.jsx/.mjs/.cjs JsObjectTokenParserparse lesexport const X = { … }/export default { … }et émet un token par feuille avec son chemin pointé (global.modeLight.high.surface.default)- Résolution des alias Style-Dictionary
{path.to.other.token} - Nouveau
TokenKind.JS_OBJECT_PATH. Insertion par défaut →'{path.to.token}' - Autocomplétion : déclenchement sur
'{prefix...oudt('prefix...dans les fichiers TS/JS. Filtrage progressif par segments du path - Inspection des hardcoded values fonctionne aussi sur TS/JS (les colors littérales
#fe5716sont flagées si un token a la même valeur)
- Nouvelles extensions scannées :
- Library : tooltip variants ne s'affichait pas (les tooltips de sous-composants d'un cell renderer ne fire pas dans une JList). Maintenant override de
JBList.getToolTipText(MouseEvent)qui calcule le tooltip directement à partir du token sous la souris. - Hardcoded : combo coupé en hauteur : row passe à 38px, combo à 26px (les descendants du font ne sont plus rognés)
- Hardcoded : colonne literal alignée : largeur fixée à 140px (avec
minimumSize), plus de flex → la flèche centrale est à la même x-coordinate sur toutes les rows. Le flex restant va à la colonne suggestion.
- Variants par token : un même
--widthdéclaré sous plusieurs@media/ classes thème est désormais conservé. Le scanner garde la première déclaration comme primaire et stocke les autres dansvariantsavec leur contexte (chaîne de sélecteurs@media (min-width: 1024px) :root,.dark-mode, etc.). Library : badge+Nà droite du nom + tooltip listant chaque variant avec sa condition. - Tooltip CSS property sur la pastille de catégorie dans le Hardcoded panel :
Used as: font-size,Used as: padding-left. Aide à comprendre la valeur en un coup d'œil. - Sections du Hardcoded panel collapsibles : clic sur le header de sélecteur → chevron
▶/▼, ligne du compteur· N. État conservé pendant la session.
- Skip des valeurs fallback :
var(--token, #307a10)→ le#307a10n'est plus signalé comme hardcoded. Détection via regexvar\(--name, FALLBACK\), range exclu deLiteralFinder. - "exact" / "≈3%" baked dans le swatch : le label séparé qui se faisait couper en largeur réduite est supprimé. Maintenant :
- Match exact = swatch propre (sans glyphe pour les couleurs, glyphe catégorie pour les autres) + tooltip
Exact match — VALUE - Match approximatif = swatch avec glyphe
≈superposé + tooltipApproximate match (≈3% off) — VALUE
- Match exact = swatch propre (sans glyphe pour les couleurs, glyphe catégorie pour les autres) + tooltip
- Ligne Hardcoded plus aérée : flèche centrée, combo réduit à 220px avec font -1pt, alignement GridBag plus prévisible.
- Alt+T sur une valeur hardcoded : l'action
Show Token Alternativesdispatch maintenant aussi sur les littéraux. Place le caret sur12pxou#fff→ popup des tokens correspondants triés par contexte CSS. Si aucun match, message clair "No matching design token for X".
- Pastilles couleur 100% rondes : nouveau composant partagé
RoundSwatchavec min/pref/max size verrouillés à un carré + paint qui prendmin(width, height)centré → cercle parfait identique partout (Library, Hardcoded values, popups). - HardcodedValuesPanel rebuild :
- Layout
GridBagLayoutà colonnes alignées :[✓] [glyph cat] [●] [literal flex] → [●] [suggestion flex] [delta 50px] [⌖] [↩] - Glyph de catégorie par row (↔ spacing, ◖ radius, T typo, ⏱ duration, ▣ shadow…) basé sur la propriété CSS détectée
- Bouton "apply" : icône
AllIcons.Diff.ApplyNotConflicts(plus explicite que MenuPaste) - Pas de scroll horizontal :
HORIZONTAL_SCROLLBAR_NEVER+ container overridegetPreferredSizepour matcher la viewport width → la colonneapplyest toujours visible - Combobox uniquement si >1 candidat (sinon JLabel flat)
- Layout
- HardcodedValuesPanel rewrite — table remplacée par une liste de row-components plus riches :
- Checkbox par row + bouton toolbar "Replace N selected" qui se met à jour avec le compteur
- Bouton Replace inline par row (icône paste à droite) → action immédiate sans toolbar
- Bouton Locate inline par row (icône target) → place le caret + sélectionne le littéral + scroll-to-center
- Headers de groupe par sélecteur CSS (
.button:hover,@media (...), etc.) — détection viaSelectorContextqui walk back jusqu'au{non-fermé - Combobox uniquement quand il y a >1 candidate ; sinon affichage flat avec swatch + nom + delta
- Swatches couleurs ronds partout :
TokenCellRenderer.SwatchIconetRoundColordu HardcodedValuesPanel paint enfillOvalau lieu defillRect. Plus moderne.
inspection/SelectorContext: helper qui retourne le sélecteur CSS englobant à un offset donné. Utilisé pour grouper les rows.
- Onglet "Hardcoded values" dans le Tool Window : nouveau Content à côté de "Library". Affiche tous les littéraux détectés dans le fichier actif, avec une table 2 colonnes :
- Colonne 1 : la valeur en dur + swatch (couleurs)
- Colonne 2 : token suggéré (combobox éditable si plusieurs candidats) + indicateur
exactou≈3%pour les couleurs proches - Sélection multiple (Ctrl/Cmd-clic, Shift-clic) + boutons toolbar Replace Selected / Replace All
- Tous les remplacements sont batchés dans un seul
WriteCommandAction(un seul Undo) - Refresh auto sur changement d'éditeur via
FileEditorManagerListener - États vides explicites : "ouvrez un fichier", "pas de hardcoded values ✓", ou "aucun token visible — configurez un scope Common"
- Tabs dans la page Settings (
JBTabbedPane) : section Scopes isolée de Triggers (Alternatives popup, Code completion, Keyboard). - Conversion d'unités px ↔ rem ↔ em dans
TokenValueIndex(base 16px) : un token--font-size-sm: 0.75remmatche désormais le littéral12px(et inversement). Résout le casfont-size: utils.rem-calc(12px)où le token cible était stocké en rem.
inspection/SuggestionEngine: extraction de la logique "trouver les meilleurs tokens pour un littéral" depuisHardcodedValueInspection. Réutilisée parHardcodedValuesPanel.
- Phase 4 — Inspection des valeurs hardcodées :
LocalInspectionToolqui détecte les hex,rgb()/hsl(), longueurs (px/rem/em/%/vh/vw/...) et durées (ms/s) directement dans les.scss/.sass/.css- Match exact : warning faible + quick-fixes "Replace with --token-X" pour chaque token de même valeur
- Match approximatif (couleurs uniquement) : si aucun token n'a la valeur exacte mais qu'une couleur est à <5% de distance RGBA, propose le plus proche avec affichage du delta (ex. "Closest design token to #ababab: --global-low-stroke-default (≈3% off)")
- Suggestion contextuelle : la propriété CSS courante (
font-size,gap,border-radius…) priorise les tokens de la catégorie attendue. Pourfont-size: 12px, le--font-size-smarrive avant un éventuel--units-smqui aurait aussi la valeur 12px. - Skip auto des fichiers source-of-truth : les fichiers déclarés dans les scopes ne s'auto-flagguent pas
- Whitelist des valeurs neutres :
0,0px,0%,100%,0s,0ms - L'inspection peut se désactiver via
Settings → Editor → Inspections → Token Flow → Hardcoded value matches a design token
- Toggle autocomplétion dans Settings → Tools → Token Flow → "Suggest design tokens in code completion". Coché par défaut. Décoché → le
CompletionContributorretourne sans rien proposer (les autres complétions IDE restent intactes). inspection/PropertyContext: helper partagé entre completion et inspection pour mapper une propriété CSS → catégorie de token attendue. DRY.
- Autocomplétion des design tokens dans les
.scss/.sass/.css:var(--…propose les CSS custom properties dont le nom matche, filtrage progressif au fil de la saisie$…(SCSS/Sass uniquement) propose les variables SCSS- Smart category : si la propriété CSS est
color/background-color/fill/stroke/etc., les tokens COLOR remontent en haut. Idem pourpadding/margin→ SPACING,border-radius→ RADIUS,box-shadow→ SHADOW,font-*/line-height→ TYPOGRAPHY,transition/animation/*-delay→ DURATION,z-index→ Z_INDEX. - Smart same-block : si une autre
var(--token-informative-…)est déjà utilisée plus haut dans le même bloc{ … }, les tokens de la familleinformativesont aussi boostés. Détection par scan inverse jusqu'au{ouvrant. - Aperçu couleur : icône swatch dans la liste de complétion pour les tokens de catégorie COLOR
- Le contributor s'enregistre sur
language="any"et filtre par extension de fichier — fonctionne en Community comme Ultimate, sans dépendance au plugin CSS
- Icône "locate" au hover des tokens dans le Dashboard : passe la souris sur un token, l'icône target apparaît à droite, clic dessus → ouvre le fichier source à la ligne de définition. Curseur main lors du survol.
- Padding bottom sur la barre de chips : 8px de marge basse pour que la scrollbar horizontale ne mange plus les chips.
- Cellules de la liste auto-fit la largeur du panneau :
JBList.getScrollableTracksViewportWidth() = true+ suppression de la largeur fixe des renderers. Plus de scroll horizontal pour voir les valeurs ; les noms longs sont clippés par Swing.
- Système de scopes — un projet peut désormais contenir plusieurs UIs (mobile/desktop/etc.) avec des design systems distincts.
- Settings → Tools → Token Flow : éditeur master-detail (liste de scopes à gauche, détails à droite)
- Chaque scope a un
name, unrootPath(relatif au projet) et sa propre liste desourcePaths rootPathvide = scope commun (toujours actif). Les scopes spécifiques s'activent quand le fichier édité est dans leur racine- Sur collision de noms (
--btn-bgdéfini dansMobileet dansCommon), le scope spécifique gagne ("specific shadows common") - Migration auto des anciens settings : la liste de chemins legacy devient un scope
Commonau premier load TokenIndexcache par scope : éditer un fichier mobile ne re-scanne pas les sources desktop
- Sections collapsibles dans le Dashboard : clic sur l'en-tête de catégorie (chevron ▶/▼) replie/déplie la section. Boutons
Expand all/Collapse alldans la toolbar. État conservé pendant la session. - FilterChip : chips de famille redessinées en pilules arrondies avec état actif visible (fond accent + texte blanc), hover effect, taille compacte. Plus aucune confusion entre actif/inactif.
- Toolbar Dashboard : icône "Clear filters" remplacée par
AllIcons.Actions.Cancel(X) + auto-désactivée quand aucun filtre n'est actif. Maintenant elle clear AUSSI le champ de recherche. - En-têtes de catégorie : affichent le compteur (ex.
COLOR · 47) à côté du titre.
- Hover popup mal positionnée : la popup s'ouvrait sur la position du caret au lieu de la position de la souris. La position écran de la souris est désormais capturée dans
mouseMovedet passée àTokenAlternativesShower.show(..., anchorScreenLocation). Visuellement la popup apparaît juste à côté du token survolé. - Hover non actif sur éditeurs déjà ouverts : le
ProjectActivitys'enregistrait viaEditorFactoryListenermais n'attachait le listener qu'aux futurs éditeurs. Désormais on parcourt aussiEditorFactory.allEditorsau démarrage pour wire-up les éditeurs préexistants. - Lien Keymap qui ne s'ouvrait pas :
ActionLinkavec lambda Kotlin ne SAM-convertit pas toujours correctement versActionListener. Remplacé parHyperlinkLabel+addHyperlinkListener. Plusieurs IDs de Configurable sont essayés en cascade pour ouvrir directement la page Keymap (variations entre versions IDEA), avec fallback sur l'ouverture par display name.
- Dashboard : filtres par famille détectée — chips toggle au-dessus de la liste, calculés automatiquement depuis les noms des tokens (ex :
global,actions,form,informative,navigation,units,shadow,radius,units…). Convention : segment[1] si segment[0] =token, sinon segment[0]. Sélectionner plusieurs chips = OR. Bouton toolbar "Clear Family Filters" pour reset. - Drag-and-drop des tokens depuis la Dashboard vers l'éditeur. Drag un token sur un fichier ouvert insère
var(--name)ou$nameà la position du drop (gestion native par l'éditeur). - Menu contextuel sur la Dashboard (clic droit) :
Insert at caret,Open source file(navigue jusqu'à la déclaration),Copy token name.
- Phase 3 — Design System Dashboard (Tool Window) :
- Nouvelle fenêtre latérale "Design Tokens" (icône palette, ancrage droit par défaut)
- Liste de tous les tokens du projet, groupés par catégorie (Color, Spacing, Typography, Shadow, Radius, Duration, Z-index, Other)
- Champ de recherche filtrant nom et valeur (live)
- Double-clic sur un token : insertion à la position du caret de l'éditeur actif (
var(--name)pour CSS custom property,$namepour SCSS variable) - Bouton Refresh dans la toolbar
- Cache d'indexation (
TokenIndexservice) :- Premier scan = à la première demande, puis cache mémoire
- Invalidation automatique sur changement VFS (
.scss/.sass/.css) - Invalidation manuelle sur Apply des settings
- Le
Alt+Test maintenant instantané au-delà du premier appel
- Hover trigger optionnel :
- Toggle dans Settings → Tools → Token Flow → "Open the alternatives popup automatically on hover"
- Délai configurable (100–5000 ms, défaut 700)
- Implémenté via
EditorMouseMotionListener+Alarm, attaché par éditeur ouvert (cleanup propre à la fermeture)
- Lien direct vers Keymap dans la page de settings ("Customize keyboard shortcut…") qui ouvre
Settings → Keymappour rebinderAlt+T.
- Logique d'affichage de la popup d'alternatives extraite dans
TokenAlternativesShower(réutilisable depuis l'action ou le hover). L'action elle-même devient minimale. - L'action
ShowAllTokensetShowAlternativespassent parTokenIndex.get()au lieu deTokenScanner.scan()direct.
- Séparateurs visuels dans la popup : les groupes de tokens (mêmes segments structurels sauf l'état) sont séparés par un en-tête. Pour
--token-actions-low-stroke-hoverla liste se présente comme :Le label affiche uniquement les segments qui divergent du pivot, joints parSTROKE --token-actions-low-stroke-default --token-actions-low-stroke-hover (pivot) ... CONTENT --token-actions-low-content-default ... HIGH › STROKE --token-actions-high-stroke-default ...›. Les séparateurs ne sont pas sélectionnables (le callback les ignore).
- Compatibilité IntelliJ IDEA Ultimate :
untilBuildretiré deplugin.xml→ le plugin charge sur toutes les versions ≥ 2024.2 (Community + Ultimate, y compris 2025.x et au-delà). Auparavant restreint à 2025.2.*.
- Settings page (par projet) —
Settings → Tools → Token Flow:- Liste éditable de fichiers/dossiers servant de "source de vérité" pour les tokens
- Chemins stockés en relatif au projet dans
.idea/designTokenSelector.xml(portable) - Fallback automatique : si la liste est vide, scan complet
.scss/.sass/.cssdu projet (comportement actuel inchangé)
- Détection des SCSS map keys — pattern
"<name>": <value>,reconnu dans les fichiers.scss/.sass. Permet de pointer directement la map source de vérité (ex :_tokens-semantics.scssStyle Dictionary). Les noms sont promus en--namepour matcher la façon dont ils seront utilisés dans le code (var(--name)).
- Tri par ordre source : dans le tier "préfixe partiel commun" (ex.
token-actions-low-*quand le pivot est*-stroke-hover),contentetsurfacese retrouvaient mixés à cause du tri secondaire par état. Le tri secondaire passe à chemin de fichier puis offset dans la source, ce qui respecte l'ordre voulu par le design system (content puis surface puis stroke, chacun en états ordonnés naturellement). - Dédup des tokens : un même
--tokenredéclaré dans plusieurs sélecteurs (:root,.dark-mode, classes de thème…) du CSS compilé apparaissait N fois dans la popup. Le scanner ne garde plus que la première occurrence par nom (typiquement la valeur du thème par défaut/light). - TokenLocator : la détection consommait les
--à gauche du caret (les tirets sont des chars d'identifiant en CSS/SCSS). Réécriture qui étend une plage d'ident autour du caret puis vérifie le prefix--ou$. - CandidateSorter : tri par proximité visuelle (HSL) mélangeait les états des familles de tokens. Nouveau tri structurel basé sur les segments du nom (
[domaine]-[famille]-[niveau]-[propriété]-[état]) :- nombre de segments communs avec le pivot (priorité décroissante)
- ordre canonique des états (
default→hover→focused→pressed→active→checked→disabled) - distance HSL en tiebreaker (couleurs uniquement)
- valeur numérique (longueurs/durées sans pivot)
- ordre alphabétique
- TokenCellRenderer : largeur de cellule fixée (560px) pour éviter que la popup prenne toute la largeur de l'éditeur.
- Popup :
setMinSize(580, 380)+dimensionServiceKeypour mémoriser la taille préférée entre sessions.
TokenStructure/TokenNameParser: parsing en segments + heuristiques d'ordre (states canonical, common-prefix scoring).
- Phase 2 — Contextual Token Picker :
TokenLocator: détection du token ($varou--var) sous le caret depuis leDocumentColorParser: parsing hex (3/4/6/8),rgb(),rgba(),hsl(),hsla()+ 11 named colorsTokenCellRenderer: rendu JList avec swatch couleur ou glyph par catégorieCandidateSorter: tri intelligent (couleurs par proximité HSL au pivot, longueurs/durées par valeur numérique, autre par nom)ShowTokenAlternativesAction: popupJBPopupChooserBuilderavec filtrage texte, pivot pré-sélectionné, remplacement viaWriteCommandAction- Raccourci clavier par défaut :
Alt+T - Action ajoutée au menu contextuel de l'éditeur
buildSearchableOptionsdésactivé (optionnel, évite le conflit avec une IDEA déjà ouverte)
- Bootstrap projet : Gradle 8.10, IntelliJ Platform Gradle Plugin 2.2.1, Kotlin 1.9.25
DesignToken/TokenCategory(8 catégories) /TokenKindTokenScanner: service projet, scan.scss/.sass/.cssviaFilenameIndex, résolution des alias avec garde anti-cycleTokenCategorizer: heuristiques nom puis valeur (regex couleurs, longueurs, durées + mots-clés)- Action
Tools → Show All Design Tokens: scan async + dialog récapitulatif groupé par catégorie - Documentation : README, ROADMAP, CHANGELOG
- Pas de dépendance aux plugins CSS/SCSS bundlés → compatible IDEA Community
- Build packageable en ZIP (~24 ko) installable via Plugins → Install from Disk