feat: resolve interaction destinations and show hover styles in design-tree#136
feat: resolve interaction destinations and show hover styles in design-tree#136
Conversation
…n-tree
Add support for fetching and displaying hover variant data:
- component-resolver: collectInteractionDestinationIds() collects all
destinationId values from ON_HOVER/CHANGE_TO interactions
- component-resolver: resolveInteractionDestinations() fetches hover
variant nodes via Figma API (batched, same pattern as component defs)
- figma-node schema: add interactionDestinations field to AnalysisFile
- loader/save-fixture: wire up interaction resolution after component defs
- figma-file-loader: preserve interactionDestinations from saved fixtures
- design-tree: output [hover] blocks showing style diffs between current
state and hover variant (background, border, opacity, shadow, text color)
Example output:
Button (INSTANCE, 120x40) [component: Button]
style: background: #2C2C2C
[hover]: background: #1E1E1E /* var:VariableID:3919:36431 */
This enables survey item #11 (hover/interaction states) to measure
actual value with real data instead of hypothetical questions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds collection and resolution of prototype interaction destination nodes, persists them in fixtures, and passes resolved interaction destinations into the design-tree renderer to produce hover-state diffs and annotate nodes with “[hover]: …”. Changes
Sequence DiagramsequenceDiagram
participant CLI as CLI (save-fixture)
participant Loader as Engine Loader
participant Resolver as Component Resolver
participant Client as Figma Client
participant FileDB as File Storage
participant Renderer as Design Tree Renderer
CLI->>Loader: request file load / save
Loader->>Resolver: resolveComponentDefinitions(file)
Resolver->>Client: getFileNodes(...) (batched)
Client-->>Resolver: component master nodes
Resolver-->>Loader: componentDefinitions
Loader->>Resolver: collectInteractionDestinationIds(document)
Resolver-->>Loader: destination IDs
Loader->>Resolver: resolveInteractionDestinations(fileKey, document, existing)
Resolver->>Client: getFileNodes(destIds...) (batched)
Client-->>Resolver: destination nodes
Resolver-->>Loader: interactionDestinations
Loader-->>FileDB: persist file (includes interactionDestinations)
FileDB-->>Renderer: load file for rendering
Renderer->>Renderer: renderNode(node, interactionDests)
Renderer->>Renderer: for ON_HOVER CHANGE_TO: computeHoverDiff()
Renderer-->>CLI: design tree output with [hover] annotations
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/core/adapters/component-resolver.ts`:
- Around line 132-163: resolveInteractionDestinations currently returns only
newly fetched nodes and omits IDs already present in existingDefinitions,
causing previously-resolved component destinations to disappear; update
resolveInteractionDestinations so the returned record includes both
existingDefinitions entries for the relevant dest IDs and the newly fetched
nodes (e.g., initialize allDestinations by copying existingDefinitions for the
collected destIds or merge existingDefinitions into allDestinations before/after
fetching), keeping the existing logic that fetches missing ids (referencing
resolveInteractionDestinations, existingDefinitions,
collectInteractionDestinationIds, and allDestinations) so callers like
loader.ts/save-fixture.ts receive a complete map.
- Around line 32-60: collectInteractionDestinationIds is currently adding every
action.destinationId; change it to only collect destinationIds for hover
interactions by checking the interaction trigger type and action navigation. In
the walk inside collectInteractionDestinationIds, only call
ids.add(action.destinationId) when the interaction object has trigger?.type ===
'ON_HOVER' (or equivalent enum) and the action has navigation === 'CHANGE_TO';
preserve existing null/undefined guards and Array.isArray checks for
n.interactions and n.children to avoid runtime errors.
In `@src/core/engine/design-tree.ts`:
- Around line 188-216: computeHoverDiff only iterates keys present in hover, so
removals or resets aren't reported; update computeHoverDiff to diff over the
union of keys between current and hover (for the root node and for each
first-level child) by building a Set of Object.keys(current) ∪
Object.keys(hover) and for each key use hover[key] if defined else emit an
explicit reset value (derive the reset/default value consistently, e.g. from
extractVisualStyles defaults or a known baseline) and push `${key}: ${value}`
(or `${cc.name}: ${key}: ${value}` for children) so style removals and
reset-to-default transitions are included.
- Around line 168-185: extractVisualStyles is recording text fills as a
"background" which causes bogus background diffs for TEXT nodes; change the
logic that sets styles["background"] from getFillInfo(node) so it does not
assign a background when node.type === "TEXT" (keep text color handling via
getFill(node) for TEXT nodes), i.e., only set styles["background"] when
fillInfo.color exists AND node.type !== "TEXT" (refer to extractVisualStyles,
getFillInfo, getFill, and the node.type === "TEXT" branch).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 6915446b-1492-4793-969a-02b8e25e0deb
📒 Files selected for processing (6)
src/cli/commands/save-fixture.tssrc/core/adapters/component-resolver.tssrc/core/adapters/figma-file-loader.tssrc/core/contracts/figma-node.tssrc/core/engine/design-tree.tssrc/core/engine/loader.ts
Ensure [hover] rendering only uses ON_HOVER + CHANGE_TO targets and that style diffs include resets/removals while avoiding bogus TEXT background diffs. Made-with: Cursor
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/core/engine/design-tree.ts`:
- Around line 227-236: The current loop compares children by array index which
yields incorrect diffs when order changes; update the logic in the block that
iterates currentNode.children and hoverNode.children (the code that uses cc =
currentNode.children[i], hc = hoverNode.children[i], extractVisualStyles and
appendStyleDiffs) to match children by stable key (preferably id, fallback to
name) instead of by index: build a lookup (map) of hover children by id/name,
iterate currentNode.children, find the corresponding hover child by id/name, and
only call extractVisualStyles/appendStyleDiffs for matched pairs; handle
unmatched children separately (new/removed) as needed and fall back to index
only when no stable key exists.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: d22808e3-c728-451f-b978-a5f4c8aa8169
📒 Files selected for processing (2)
src/core/adapters/component-resolver.tssrc/core/engine/design-tree.ts
Made-with: Cursor
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/core/engine/design-tree.ts`:
- Around line 245-251: The loop over currentNode.children uses the loop index i
to access hoverUnmatchedByIndex which causes index drift when keyed children are
present; introduce a separate unkeyed counter (e.g., unkeyedIdx) initialized
before the loop and, inside the loop, when getChildStableKey(cc) returns falsy,
use hoverUnmatchedByIndex[unkeyedIdx] and increment unkeyedIdx only in that
branch—keep using hoverByStableKey.get(stableKey) for keyed children and do not
advance unkeyedIdx for them so unkeyed matches stay aligned with
hoverUnmatchedByIndex.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 4cbbb66e-5c9e-442b-a8af-007d68fb3a6a
📒 Files selected for processing (1)
src/core/engine/design-tree.ts
Use separate unkeyedIdx counter for fallback matching instead of the loop index i, which drifts when keyed children precede unkeyed ones. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/core/engine/design-tree.ts`:
- Around line 217-257: getChildStableKey currently returns id first which masks
name-based matching because id is always present; change getChildStableKey to
prefer a stable semantic key (e.g., name-based key like `name:${node.name}` when
name exists) and fall back to id only when name is absent so computeHoverDiff
can match variant children whose ids differ; update getChildStableKey (and any
callers such as computeHoverDiff) to use the new preference so
hoverByStableKey/unkeyed matching can find corresponding hover children.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 7ed95740-ddea-4ed1-ace2-d08d911365ca
📒 Files selected for processing (1)
src/core/engine/design-tree.ts
Variant children share the same name but have different ids. Using name-first matching ensures hover diffs correctly pair corresponding children across default and hover variants. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Enable hover variant data in the design-tree so AI can implement
:hoverCSS from actual Figma data.What changed
collectInteractionDestinationIds()andresolveInteractionDestinations()— collectsdestinationIdfromON_HOVER → CHANGE_TOinteractions and fetches the variant nodes via Figma APIinteractionDestinationsfield onAnalysisFile[hover]:blocks showing style differences between current state and hover variantExample output
Why
interactionswithdestinationId— we just hadn't been resolving those destinationsdesktop-product-detailfixtureVerified
Resolved 5 interaction destination(s)✅[hover]:blocks with style diffs ✅Test plan
save-fixtureresolves interaction destinationsimplementoutputs[hover]:lines in design-treeinteractionDestinationsin data.json🤖 Generated with Claude Code
Summary by CodeRabbit