Gradient token support for studio users#3918
Conversation
|
|
🛡️ Hyma Compliance Check ✅ No compliance-relevant changes detected 25 file(s) scanned · 0 findings This PR adds a new "gradient" token type (UI form, tooltip rendering, Figma paint-style matching, type definitions). All changes are local data-model/UI logic for the plugin — no new external API calls, no sync-provider or OAuth changes, no new personal-data storage, and no secrets/credentials introduced.
|
|
Commit SHA:2c5181c92205449dab51bc2b3e866e49c33755e3 Test coverage results 🧪
|
|
Commit SHA:2c5181c92205449dab51bc2b3e866e49c33755e3 |
|
|
There was a problem hiding this comment.
Pull request overview
This PR adds end-to-end support for gradient tokens coming from the Tokens Studio OAuth (REST) sync path, so they can be displayed, previewed, edited, and applied similarly to existing color tokens (while remaining excluded from Figma Variable creation).
Changes:
- Introduces
TokenTypes.GRADIENTacross the token type system (types, guards, schema defs) and enables rendering/preview viagradientTokenToCss+ a simplified tooltip summary. - Extends style application and value mapping to handle gradient token values (including structured gradient objects) when creating/applying paint styles and node fills/strokes.
- Adds a dedicated gradient token edit form UI (stop editor + draggable stop bar) and shows gradient-related Figma scope metadata.
Reviewed changes
Copilot reviewed 33 out of 33 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/tokens-studio-for-figma/src/utils/trimValue.ts | Preserves structured gradient values while still trimming alias strings. |
| packages/tokens-studio-for-figma/src/utils/trimValue.test.ts | Adds tests for gradient trim/pass-through behavior. |
| packages/tokens-studio-for-figma/src/utils/is/isSingleGradientToken.ts | Adds type guard for gradient tokens (object or alias string). |
| packages/tokens-studio-for-figma/src/utils/is/index.ts | Re-exports the new gradient type guard. |
| packages/tokens-studio-for-figma/src/utils/color/index.ts | Exposes gradient-to-CSS utilities from the color utils barrel. |
| packages/tokens-studio-for-figma/src/utils/color/gradientTokenToCss.ts | Converts structured gradient objects (incl. REST color objects) into CSS gradients and summaries. |
| packages/tokens-studio-for-figma/src/utils/color/gradientTokenToCss.test.ts | Adds unit tests for gradient CSS/summary helpers. |
| packages/tokens-studio-for-figma/src/types/values/TokenGradientValue.ts | Introduces the gradient value/stops type. |
| packages/tokens-studio-for-figma/src/types/values/index.ts | Re-exports TokenGradientValue. |
| packages/tokens-studio-for-figma/src/types/tokens/SingleToken.ts | Extends SingleToken union to include gradient tokens. |
| packages/tokens-studio-for-figma/src/types/tokens/SingleGradientToken.ts | Adds the SingleGradientToken type. |
| packages/tokens-studio-for-figma/src/types/tokens/index.ts | Re-exports SingleGradientToken. |
| packages/tokens-studio-for-figma/src/types/tokens/EditTokenObject.ts | Allows gradient tokens in the edit-token object union. |
| packages/tokens-studio-for-figma/src/plugin/updateStyles.ts | Includes gradient tokens in the style creation/update pipeline (gated by settings). |
| packages/tokens-studio-for-figma/src/plugin/setColorValuesOnTarget.ts | Allows applying structured gradient values by converting them to CSS strings before gradient parsing. |
| packages/tokens-studio-for-figma/src/plugin/node.ts | Flattens resolved gradient token values to CSS strings when mapping values for plugin operations. |
| packages/tokens-studio-for-figma/src/plugin/figmaUtils/styleMatchers/paintStyleMatchesColorToken.ts | Normalizes gradient values when comparing tokens to paint styles. |
| packages/tokens-studio-for-figma/src/constants/VariableTypes.ts | Adds tokenTypesWithFigmaSection so gradients show metadata without enabling variables. |
| packages/tokens-studio-for-figma/src/constants/TokenTypes.ts | Adds GRADIENT to the TokenTypes enum. |
| packages/tokens-studio-for-figma/src/constants/FigmaVariableMetaData.ts | Adds gradient-related scopes to TOKEN_TYPE_TO_SCOPES_MAP. |
| packages/tokens-studio-for-figma/src/config/tokenType.defs.json | Adds a “gradient” token type definition for UI/schema metadata. |
| packages/tokens-studio-for-figma/src/app/store/useTokens.tsx | Treats GRADIENT similarly to gradient-valued COLOR when deciding style creation. |
| packages/tokens-studio-for-figma/src/app/hooks/usePropertiesForType.ts | Adds fill/border properties for gradient tokens. |
| packages/tokens-studio-for-figma/src/app/components/TokenTooltip/TokenTooltipContentValue.tsx | Routes gradient tokens to a new tooltip value display. |
| packages/tokens-studio-for-figma/src/app/components/TokenTooltip/SingleGradientValueDisplay.tsx | Renders a summary tooltip line for gradients. |
| packages/tokens-studio-for-figma/src/app/components/Tokens.tsx | Hides “create gradient token” UI unless the storage provider supports it (still displays existing ones). |
| packages/tokens-studio-for-figma/src/app/components/TokenListing.tsx | Initializes default values for new gradient tokens. |
| packages/tokens-studio-for-figma/src/app/components/TokenButton/TokenButtonContent.tsx | Adds gradient swatch rendering in token pills (CSS var background). |
| packages/tokens-studio-for-figma/src/app/components/TokenButton/StyledTokenButton.tsx | Adds GRADIENT styling variants for pill rendering in LIST/GRID modes. |
| packages/tokens-studio-for-figma/src/app/components/GradientTokenForm.tsx | Adds a full gradient editor form (kind/geometry/stops/alias mode). |
| packages/tokens-studio-for-figma/src/app/components/GradientStopBar.tsx | Adds interactive stop bar UI (drag-to-reposition + click-to-add). |
| packages/tokens-studio-for-figma/src/app/components/FigmaVariableForm.tsx | Shows the Figma metadata section for gradient tokens via tokenTypesWithFigmaSection. |
| packages/tokens-studio-for-figma/src/app/components/EditTokenForm.tsx | Integrates GradientTokenForm into the edit form switch. |
|
claude review : Local max-effort review — 15 findingsRan a multi-agent review (10 finder angles → 13 verifiers → gap sweep) over the branch. All 15 findings below survived verification. Ranked most-severe first; 🔴 Critical — data corruption / broken exports1. Rename any token → every gradient token is corrupted — The composite-object branch flattens each top-level Trigger: rename 2. Gradient-of-alias exports as a black solid paint —
Trigger: gradient token B = 3. rgba() stops misalign variable references —
Trigger: 4. Conic gradients never match their own style — Matcher only handles Trigger: conic gradient exported once, then re-checked → never matches; raw paints re-applied every time. 🟠 High — silent behavioural drift5. Form geometry fields are inert; diamond exports as linear —
Trigger: edit Center X/Y or create a diamond gradient → exported paint ignores the geometry / is a 45° linear, no warning. 6. Null-valued gradient crashes the tooltip —
Trigger: malformed remote JSON with 7. Renamed/deleted gradient tokens leak paint styles — Rename dialog offers Rename style only for
Fix: add 8. Negative conic startAngle silently becomes 0 — Emits Trigger: type -45 into Start Angle → preview shows -45°, exported paint is 0°. 9. Chained-alias mode toggle overwrites token with default —
Fix: use 🟡 Medium — UX / robustness10. No validation on gradient save —
Trigger: clear a stop's color to 11.
12. Stop list keyed by index — picker sticks; selection shifts —
Trigger: open picker on stop 2, remove stop 1 → picker on wrong stop; select stop 3, remove stop 1 → selection is now on the old stop 4. 13. Drag doesn't recover if pointer leaves the iframe — Document Trigger: re-entering the iframe makes the stop follow the cursor with no button pressed; the ending click lands on the track and adds a spurious stop. 14. Aliases resolving to objects render
Trigger: stop color |
Gradient token review — fix statusCommit: ✅ Fixed in this commit (12 of 15 findings)Critical
High
Medium
🟡 Remaining — needs deeper refactor (follow-up ticket)5 Form geometry fields are inert; diamond exports as linear
Additionally, Why deferred: the current export path is Impact until fixed: users editing geometry fields see no effect in exports; diamond tokens export as 45° linear gradients without warning; two tokens differing only in these fields collide against the same paint style. Test status
|
|
🛡️ Hyma Compliance Check ✅ No compliance-relevant changes detected 30 file(s) scanned · 0 findings
|
1 similar comment
|
🛡️ Hyma Compliance Check ✅ No compliance-relevant changes detected 30 file(s) scanned · 0 findings
|
|
🛡️ Hyma Compliance Check ✅ No compliance-relevant changes detected 30 file(s) scanned · 0 findings
|
2 similar comments
|
🛡️ Hyma Compliance Check ✅ No compliance-relevant changes detected 30 file(s) scanned · 0 findings
|
|
🛡️ Hyma Compliance Check ✅ No compliance-relevant changes detected 30 file(s) scanned · 0 findings
|
Why does this PR exist?
Closes #0000
Adds display and export support for gradient tokens synced from Tokens Studio via Studio OAuth (REST API). Gradient tokens were already a known type in the plugin but had no mapping or rendering for the OAuth sync path — they showed blank pills,
[object Object]in tooltips, broke the edit form, and could not be exported as Figma paint styles.What does this pull request do?
Type system & ingestion
TokenTypes.GRADIENTto theTokenTypesenum and maps the incoming'gradient'type string from the Studio REST API vianormalizeTokenTypeTokenGradientValuetype andSingleGradientTokento the token type system{ colorSpace, components, hex?, alpha? }rather than plain hex strings —resolveStopColorextracts a usable CSS color from them (prefershex, otherwise computesrgb()/rgba()fromcomponents)Rendering
gradientTokenToCssandgradientTokenSummaryutilities for converting gradient objects to CSS strings and human-readable summariesvar(--backgroundColor)on the::beforeswatch, matching the color token pill pattern, withStyledTokenButtonGRADIENT variant stylesradial, 180°, 3 stops) instead of per-stop color rowsEdit form
GradientTokenForm(kind selector, stop list, draggableGradientStopBar, geometry inputs) with alias-mode toggletokenTypesWithFigmaSectionconstant so gradient tokens show the Figma scopes section without being included intokenTypesToCreateVariable(gradient tokens cannot be Figma Variables)ALL_FILLS,FRAME_FILL,SHAPE_FILL,TEXT_FILL,STROKE_COLOR,EFFECT_COLOR) toTOKEN_TYPE_TO_SCOPES_MAP[]scope arrays when deciding whether to show the expanded state-/.doesn't snap to0; positions are clamped to[0, 1]handleRemoveStopdecrements the selection index when removing a stop above itGradientStopBardrag usessetPointerCapture+pointercancelso releasing outside the plugin iframe cleans up correctlyExport as paint styles
updateStyles/updateColorStylesfilter to includeTokenTypes.GRADIENTwhenstylesGradientis enabledsetColorValuesOnTargetroutes gradient-type tokens (including alias-of-gradient) through the gradient paint builder rather than the solid pathpaintStyleMatchesColorTokenacceptsstring | TokenGradientValue, collapses linear/radial branches, and handlesGRADIENT_ANGULAR/GRADIENT_DIAMONDconvertConicGradientregex widened to accept negative and leading-decimal anglesgetReferenceTokensFromGradientsplit is paren-aware sorgb()/rgba()stop colors no longer misalign variable references withgradientStopsTokenTypes.GRADIENTto the choice arrays)Robustness
isSingleGradientTokennull-checks before theinoperator so a malformed token withvalue: nulldoesn't crash the tooltipupdateAliasesInStategets a gradient-aware branch that only updatesstop.colorreference strings, so renaming an unrelated token no longer stringifiesstops/center/start/endviatoString()Testing this change
radial, 180°, 3 stopswith no color swatchesAdditional Notes (if any)
Gradient tokens have
variableType: nullin the Studio schema — they are intentionally excluded from Figma Variable creation. The Figma scopes section is shown for metadata purposes only (e.g. for style application), not for variable creation.Stop color objects are a DTCG-compatible format (
{ colorSpace, components, alpha? }). TheresolveStopColorhelper prefers thehexshortcut if present, otherwise computesrgb()/rgba()from thecomponentsarray (0–1 floats).Known limitation — follow-up ticket: the form exposes editable geometry fields (per-stop
midpoint,center,radius,size, linearstart/end) that the CSS-string export path currently ignores;kind: 'diamond'also falls back tolinear-gradient(45deg, ...)because CSS has no diamond equivalent. Fixing these properly means routing export through a directTokenGradientValue → GradientPaintbuilder rather than the CSS round-trip.