Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/okotoki/figma-messenger

Type-safe communication for good 🧐.
https://github.com/okotoki/figma-messenger

emitter figma figma-plugins typescript

Last synced: 3 months ago
JSON representation

Type-safe communication for good 🧐.

Lists

README

        

# Type-safe Iframe ↔ Main Thread communication for good 🧐

## Usage

Installation
```sh
npm i figma-messenger
# or using Yarn
yarn add figma-messenger
```

Quick usage example
```typescript
// Shared code between main thread and iframe
// shared.ts
interface IframeToMain {
setVersion(name: string, value: number): void
}

interface MainToIframe {
heyIframe(data: any): void
}

// main.ts
import { createMainThreadMessenger } from 'figma-messenger'

const mainMessenger = createMainThreadMessenger()

// All good
mainMessenger.send('heyIframe', { any: 'data'})

// Error. Argument of type "unknownMessage" is not assignable to parameter of type "heyIframe".
mainMessenger.send('unknownMessage')
// Error. Expected 2 arguments, but got 1.
mainMessenger.send('heyIframe')

mainMessenger.on('setVersion', (name, value) => {
console.log('setVersion', name, value)
})

// Remove all listeners
mainMessenger.off('setVersion')

// iframe.ts
import { createIframeMessenger, createMainThreadMessenger } from 'figma-messenger'

const iframeMessenger = createIframeMessenger()

// All good
iframeMessenger.send('setVersion', 'initial', 1)

// Error. Expected 3 arguments, but got 2.
iframeMessenger.send('setVersion', 'initial')

iframeMessenger.on('heyIframe', sel => console.log(sel))

// Remove all listeners
iframeMessenger.off('heyIframe')
```

See more comprehensive live figma plugin example at [examples/figma-plugin](examples/figma-plugin).
Files `shared/types.ts`, `app.tsx` and `main/index.ts`

## Api

### createIframeMessenger(name?: string) / createMainThreadMessenger(name?: string)

Creates a messenger instance for Iframe and Main Thread sides respectively.
Optional `name` argument. If not set, messenger will be global. Otherwise only will receive events from the messenger with the same name.
Also, takes 2 type arguments:
`MessagesToSend` – messages to send signature
`MessagesToListen` – messages to receive signature

Example:
```typescript
// Messages sent from Iframe side, received on Main Thread side
interface IframeToMain {
setVersion(name: string, value: number): void
}

// Messages sent from Main Thread side, received on Iframe side
interface MainToIframe {
heyIframe(data: any): void
}

/**
* somewhere in iframe code:
*/

// global messenger
const iframeMessenger = createIframeMessenger()
// named messenger. Will communicate only to messenger with the same name on main thread.
const namedIframeMessenger = createIframeMessenger('SPECIAL')

/**
* somewhere in main thread code:
*/

// global messenger
const mainThreadMessenger = createMainThreadMessenger()

// named messenger. Will communicate only to messenger 'SPECIAL' on iframe side.
const namedMainThreadMessenger = createMainThreadMessenger('SPECIAL')
```

Single global listener under the hood makes it possible to create multiple instances, which won't conflict, but would handle messages with same name.
```typescript
const m1 = createIframeMessenger()
const m2 = createIframeMessenger()
const m3 = createIframeMessenger('SPECIAL')

// When fired globally, "msg" message would be received by m1 and m2, but not by m3.
m1.on('msg', callback1) // receives global message
m2.on('msg', callback2) // receives global message

m3.on('msg', callback3) // only will receive from messenger named 'SPECIAL' on main thread side
```

### .on(message: string, listener: (...arg: any[]) => void): void
Add listener for the message from opposite side.
Callbacks can take no or multiple arguments.
```typescript
messenger.on('aMessage', handleMessage)
messenger.on('someMessage', (data) => doSomething(data))
messenger.on('otherMessage', (arg1, arg2) => hello(arg1, arg2))
messenger.on('noArgsMessage', () => world())
```

### .off(message: string, , listener: (...arg: any[]) => void): void
Remove one or all listeners for the message.
```typescript
// remove particular listener
messenger.off('aMessage', handleMessage)

// remove all listeners
messenger.on('someMessage')
```

### .send(message: string, ...data?: any[]): void
Send a message to an opposite side.
```typescript
// send message with one data item
messenger.on('someMessage', data)
// with multiple data items
messenger.on('otherMessage', arg1, arg2)
// or no data at all
messenger.send('noArgsMessage')
```

## License
MIT