Figma Support Forum

Reactions: Make prototype connections editable via API

It would be super powerful if reactions could be created or modified by plugins, so I’m curious why it’s read-only.

2 Likes

Yeah, I don’t understand this read-only [Reaction { action: Action, trigger: Trigger }] neither, I even tried to set the action & trigger which is not read-only, but it gives this "TypeError: 'action' is read-only" error at run time :sob:

100% agreed! I was working on a plugin to standardize our animation timings for our design system. Got all the way to the end of it, but got a “There’s no setter for this property” error.

Here’s my code. Figma Genie! Please make this work!

export async function setTransitions(transition) {

    const page = figma.currentPage;
    const selection = page.selection;
    let checkTransitions = [];

    // Get our list of nodes within the selection that have transitions
    for (const node of selection){
        
        if (node.type == "GROUP" || node.type == "COMPONENT_SET" || node.type == "COMPONENT" || node.type == "FRAME" || node.type == "INSTANCE"){
            checkTransitions = node.findAll( (thisNode) => { 
                if (thisNode.type != "SLICE" && thisNode.type != "GROUP" && thisNode.type != "COMPONENT_SET"){
                    if ( thisNode.reactions.length >0 ) {
                        return true;
                    }
                }
                return false;
            });
        }
        if (node.type != "SLICE" && node.type != "GROUP" && node.type != "COMPONENT_SET"){
            if ( node.reactions.length >0 ) {
                checkTransitions.push(node);
            }
        }
    }

    // Set the transitions on every selected node -> reaction
    for (const node of checkTransitions){
        let newReactions = [];
        for (const reaction of node.reactions){
            if(reaction.action.type == "NODE"){
                let action;
                if( reaction.action.transition.type != "DISSOLVE" && reaction.action.transition.type.indexOf("ANIMATE")<0 ){
                    action = <Action>{
                        type: "NODE",
                        destinationId: reaction.action.destinationId,
                        navigation: reaction.action.navigation,
                        preserveScrollPosition: reaction.action.preserveScrollPosition,
                        transition: <DirectionalTransition>{
                            type: reaction.action.transition.type,
                            duration: transitions[transition].duration,
                            easing: transitions[transition].easing,
                            direction: reaction.action.transition.direction,
                            matchLayers: reaction.action.transition.matchLayers,
                        },
                        overlayRelativePosition: (typeof(reaction.action.overlayRelativePosition)==="undefined"?null:reaction.action.overlayRelativePosition),
                    }
                } else {
                    action = <Action>{
                        type: "NODE",
                        destinationId: reaction.action.destinationId,
                        navigation: reaction.action.navigation,
                        preserveScrollPosition: reaction.action.preserveScrollPosition,
                        transition: <SimpleTransition>{
                            type: reaction.action.transition.type,
                            duration: transitions[transition].duration,
                            easing: transitions[transition].easing,
                        },
                        overlayRelativePosition: (typeof(reaction.action.overlayRelativePosition)==="undefined"?null:reaction.action.overlayRelativePosition),
                    }
                }
                newReactions.push({action: action, trigger: reaction.trigger });
            }
        }
        node.reactions = newReactions; // This line gives the "no setter" error
    }
}

I also started building a plugin to generate a card sort prototype for concept user testing. Realized it was read-only, and had to scrap everything.