Hey everyone,
I’m working on a Figma Plugin and found it challenging to communicate between the UI (iframe) and Plugin (sandbox) layer in a typesafe way. So, I created figma-connect
, a lightweight wrapper to streamline this communication process.
Would appreciate your thoughts! Thanks 🙂
Example Usage
shared.ts
import { type TFromPluginMessageEvent } from 'figma-connect/plugin';
import { type TFromAppMessageEvent } from 'figma-connect/app';
// Plugin Events (Plugin -> App)
interface TOnSelectNodeEvent extends TFromPluginMessageEvent {
key: 'on-select-node';
args: { selected: Pick<SceneNode, 'name' | 'id'>t] };
}
interface TOnDeselectNodeEvent extends TFromPluginMessageEvent {
key: 'on-deselect-node';
args: { deselected: Pick<SceneNode, 'name' | 'id'>t] };
}
type TFromPluginMessageEvents = TOnSelectNodeEvent | TOnDeselectNodeEvent;
// App Events (App -> Plugin)
interface TOnUIRouteChangeEvent extends TFromAppMessageEvent {
key: 'on-ui-route-change';
args: {
activeRoute: 'a' | 'b' | 'c';
};
}
interface TOnUserLoginEvent extends TFromAppMessageEvent {
key: 'on-user-login';
args: {
userId: string;
timestamp: number;
};
}
type TFromAppMessageEvents = TOnUIRouteChangeEvent | TOnUserLoginEvent;
app.ts
(or ui.ts
)
import { FigmaAppHandler } from 'figma-connect/app';
import { TFromPluginMessageEvents, TFromAppMessageEvents } from './shared';
// Create App Handler and pass global 'parent' instance as first argument
const appHandler = new FigmaAppHandler<TFromPluginMessageEvents, TFromAppMessageEvents>(parent);
// Send Events to the 'plugin' part
appHandler.post('on-ui-route-change', { activeRoute: 'a' });
appHandler.post('on-user-login', { userId: 'user123', timestamp: Date.now() });
// Register callbacks to receive Events from the 'plugin' part
appHandler.register({
key: 'on-select-node',
type: 'plugin.message',
callback: async (_, args) => {
console.log('Selected Nodes:', args.selected);
},
});
appHandler.register({
key: 'on-deselect-node',
type: 'plugin.message',
callback: async (_, args) => {
console.log('Deselected Nodes:', args.deselected);
},
});
plugin.ts
(or code.ts
)
import { FigmaPluginHandler } from 'figma-connect/plugin';
import { TFromAppMessageEvents, TFromPluginMessageEvents } from './shared';
// Create Plugin Handler and pass global 'figma' instance as first argument
const pluginHandler = new FigmaPluginHandler<TFromAppMessageEvents, TFromPluginMessageEvents>(figma);
// Send Events to the 'app/ui' part
pluginHandler.post('on-select-node', { selected: :{ id: '1v1', name: 'Frame1' }] });
pluginHandler.post('on-deselect-node', { deselected: :{ id: '1v1', name: 'Frame1' }] });
// Register callbacks to receive Events from the 'app/ui' part
pluginHandler.register({
key: 'on-ui-route-change',
type: 'app.message',
callback: async (_, args) => {
console.log('UI Route Changed:', args.activeRoute);
},
});
pluginHandler.register({
key: 'on-user-login',
type: 'app.message',
callback: async (_, args) => {
console.log('User Logged In:', args.userId, 'at', args.timestamp);
},
});
Source: monorepo/apps/figma-plugin at develop · dyn-art/monorepo · GitHub
by inbeta.group and dyn.art