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.

3 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.

With the new addition of flows, the ability to programmatically set these would be great.

Trying also to get destinationId from Action but it won’t work. Any workarounds to safely get the destinationId or any other property figma doesnt expose?

Looks like it’s available now! Blog · Figma Developers

1 Like