Skip to content

Instantly share code, notes, and snippets.

@Amareis
Last active April 26, 2022 12:13
Show Gist options
  • Select an option

  • Save Amareis/40eb6dbe6f4dfa6ac1f5fdacc65ac632 to your computer and use it in GitHub Desktop.

Select an option

Save Amareis/40eb6dbe6f4dfa6ac1f5fdacc65ac632 to your computer and use it in GitHub Desktop.
Простой интероп между плагином фигмы и его UI. Основан на прокси, полностью типизирован, результат метода автоматически заворачивается в Promise
type Handlers = Record<string, (...args: any) => void>
const isPlugin = typeof figma !== 'undefined'
const res: Record<number, (t: any) => void> = {}
export function handlers<T extends Handlers>(methods: T): T {
const t = isPlugin ? figma.ui : window
t.onmessage = async (m: any) => {
const { method, args } = m.data ? m.data.pluginMessage.pluginMessage : m
if (method === 'RESPONSE') {
res[args[0]]?.(args[1])
delete res[args[0]]
} else {
const r = await methods[method]?.(...args.slice(1))
void post('RESPONSE', [args[0], r])
}
}
return methods
}
let i = 1
const post = (method: string, args: any[]) => {
const n = i++
const t = isPlugin ? figma.ui : parent
t.postMessage(
{ pluginMessage: { method, args: method === 'RESPONSE' ? args : [n, ...args] } },
isPlugin ? undefined : ('*' as any),
)
if (method !== 'RESPONSE')
return new Promise((ok) => {
res[n] = ok
})
}
type WrapPromise<T extends Handlers> = {
[M in keyof T]: (...args: Parameters<T[M]>) => Promise<Awaited<ReturnType<T[M]>>>
}
export function makeBridge<T extends Handlers>(): WrapPromise<T> {
return new Proxy({} as WrapPromise<T>, {
get(_, method) {
return (...args: any[]) => {
return post(method as string, args)
}
},
})
}
import { handlers, makeBridge } from './bridge'
import type { Ui } from './ui'
const wait = (n = 100) => new Promise((ok) => setTimeout(ok, n))
const pluginHandlers = handlers({
//метод для получения или установки значений из локального хранилища, для примера
async val(key: string, value?: string): Promise<string | undefined> {
if (value !== undefined) {
await figma.clientStorage.setAsync(key, value)
return value
}
const v = await figma.clientStorage.getAsync(key)
if (v) return v
return undefined
},
})
export type Plugin = typeof pluginHandlers
const ui = makeBridge<Ui>()
async function openUi() {
const size = { width: 280, height: 352 }
figma.showUI(__html__, size)
await wait(200)
await ui.openSettings()
}
void openUi()
import { handlers, makeBridge } from '../bridge'
import type { Plugin } from '../plugin'
export const plugin = makeBridge<Plugin>()
const uiHandlers = handlers({
async openSettings() {
await plugin.val('key', 'value')
await plugin.val('key') // === 'value'
},
})
export type Ui = typeof uiHandlers
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment