diff --git a/app/lib/screens/layout-view/index.tsx b/app/lib/screens/layout-view/index.tsx index 907e547f..fe74405f 100644 --- a/app/lib/screens/layout-view/index.tsx +++ b/app/lib/screens/layout-view/index.tsx @@ -1,5 +1,7 @@ import React from "react"; +import { PluginSdk } from "../../utils/plugin-provider/plugin-app-sdk"; export default function LayoutViewScreen() { + PluginSdk.selectedNodeId; return

Layout view

; } diff --git a/app/lib/utils/plugin-provider/events.ts b/app/lib/utils/plugin-provider/events.ts index 12572137..a4bc51e2 100644 --- a/app/lib/utils/plugin-provider/events.ts +++ b/app/lib/utils/plugin-provider/events.ts @@ -3,6 +3,7 @@ export const PLUGIN_SDK_NS_RESPONSE_ALL = "bridged/response/*"; export const PLC_REMOTE_API_REQ = "pugin-consumer/remote-api/request"; export const PLC_REMOTE_API_RES = "pugin-consumer/remote-api/response"; export const PLUGIN_SDK_NS_REMOTE_API = `${PLUGIN_SDK_NAMESPACE_BASE_TOKEN}/remote-api`; +export const PLUGIN_SDK_NS_GENERAL_STATE_DATA = `${PLUGIN_SDK_NAMESPACE_BASE_TOKEN}/general-state-data`; // region sync export const PLUGIN_SDK_NS_SYNC = `${PLUGIN_SDK_NAMESPACE_BASE_TOKEN}/sync`; @@ -46,6 +47,9 @@ export interface BasePluginEvent { data: T; } +/** + * An Event object interface to pass Plugin events from / to PluginService and PluginApp + */ export interface TransportPluginEvent extends BasePluginEvent { origin: "app" | "server"; type: "response" | "request"; diff --git a/app/lib/utils/plugin-provider/plugin-app-sdk/index.ts b/app/lib/utils/plugin-provider/plugin-app-sdk/index.ts index 02244e34..825d19d7 100644 --- a/app/lib/utils/plugin-provider/plugin-app-sdk/index.ts +++ b/app/lib/utils/plugin-provider/plugin-app-sdk/index.ts @@ -20,6 +20,7 @@ import { import { NotifyRequest } from "../interfaces/notify/notify.requests"; import { nanoid } from "nanoid"; import { DragAndDropOnCanvasRequest } from "../interfaces/dragdrop/dragdrop.requests"; +import { ReflectSceneNode } from "@bridged.xyz/design-sdk/lib/nodes"; export class PluginSdk { static window: Window; @@ -28,15 +29,26 @@ export class PluginSdk { } // region general canvas api - static get selectedNodes(): string { + static get selectedNodeIds(): readonly string[] { throw "not implemented"; - return ""; + return []; } - static get selectedNode(): string { + static get selectedNodes(): readonly ReflectSceneNode[] { + throw "not implemented"; + return []; + } + + static get selectedNodeId(): string { + // TODO + throw "not implemented"; + return undefined; + } + + static get selectedNode(): ReflectSceneNode { // TODO throw "not implemented"; - return ""; + return undefined; } // enderegion general canvas api diff --git a/app/lib/utils/plugin-provider/plugin-server/index.ts b/app/lib/utils/plugin-provider/plugin-service/index.ts similarity index 96% rename from app/lib/utils/plugin-provider/plugin-server/index.ts rename to app/lib/utils/plugin-provider/plugin-service/index.ts index 33481ecd..1b448991 100644 --- a/app/lib/utils/plugin-provider/plugin-server/index.ts +++ b/app/lib/utils/plugin-provider/plugin-service/index.ts @@ -35,10 +35,10 @@ interface HanderProps { } figma.on("selectionchange", () => { - PluginSdkServer.onSelectionChange(); + PluginSdkService.onSelectionChange(); }); -export class PluginSdkServer { +export class PluginSdkService { static onSelectionChange() { const selection = figma.currentPage.selection; if (selection.length == 0) { @@ -69,11 +69,11 @@ export class PluginSdkServer { } static handleDragAndDropEvent(key: string, data: any, position: { x; y }) { - if (!PluginSdkServer.dragAndDropHandlers.has(key)) { + if (!PluginSdkService.dragAndDropHandlers.has(key)) { throw `no handler found for event ${key} on drag and drop handler`; } - PluginSdkServer.dragAndDropHandlers.get(key)(data, position); + PluginSdkService.dragAndDropHandlers.get(key)(data, position); } static handle(event: TransportPluginEvent): boolean { @@ -292,5 +292,5 @@ function handleDragDropped(props: HanderProps) { const x = bounds.x + xFromCanvas / zoom - offset.x; const y = bounds.y + yFromCanvas / zoom - offset.y; - PluginSdkServer.handleDragAndDropEvent(eventKey, customData, { x: x, y: y }); + PluginSdkService.handleDragAndDropEvent(eventKey, customData, { x: x, y: y }); } diff --git a/app/lib/utils/plugin-provider/pugin-app/README.md b/app/lib/utils/plugin-provider/pugin-app/README.md new file mode 100644 index 00000000..c5fe9a65 --- /dev/null +++ b/app/lib/utils/plugin-provider/pugin-app/README.md @@ -0,0 +1,7 @@ +# Plugin SDK React component + +```tsx + + + +``` diff --git a/app/lib/utils/plugin-provider/pugin-app/index.tsx b/app/lib/utils/plugin-provider/pugin-app/index.tsx index ebe5d52b..3a141123 100644 --- a/app/lib/utils/plugin-provider/pugin-app/index.tsx +++ b/app/lib/utils/plugin-provider/pugin-app/index.tsx @@ -1,14 +1,17 @@ import React, { useEffect } from "react"; +import { useSetRecoilState } from "recoil"; import Axios from "axios"; import { PLC_REMOTE_API_REQ, PLC_REMOTE_API_RES, PLUGIN_SDK_NAMESPACE_BASE_TOKEN, + PLUGIN_SDK_NS_GENERAL_STATE_DATA, PLUGIN_SDK_NS_REMOTE_API, TransportPluginEvent, } from "../events"; import { NetworkRequest } from "../interfaces/remote-api/remote-api.requests"; import { PluginSdk } from "../plugin-app-sdk"; +import { currentlySelectedPrimaryNodeId } from "./states/canvas"; export function PluginApp(props: { children: any }) { useEffect(() => { @@ -30,33 +33,9 @@ export function PluginApp(props: { children: any }) { } // endregion validate - PluginSdk.handle(message); - - if (message.namespace == PLUGIN_SDK_NS_REMOTE_API) { - // call remote request - const requestManifest = message.data as NetworkRequest; - Axios.request({ - method: requestManifest.method, - url: requestManifest.url, - data: requestManifest.data, - headers: requestManifest.headers, - }) - .then((r) => { - networkResponseToCodeThread( - window, - requestManifest.requestId, - r.data - ); - }) - .catch((e) => { - networkResponseToCodeThread( - window, - requestManifest.requestId, - null, - e - ); - }); - } + registerPluginSdkHandler(message); + registerPluginGlobalStateHandler(message); + registerPluginRemoteCallHandler(message); }); console.info("PluginApp initiallized"); @@ -65,6 +44,47 @@ export function PluginApp(props: { children: any }) { return
{props.children}
; } +function registerPluginSdkHandler(message: TransportPluginEvent) { + PluginSdk.handle(message); +} + +/** + * registers global state handler managed by plugin. such like current selection. + */ +function registerPluginGlobalStateHandler(message: TransportPluginEvent) { + if (message.namespace == PLUGIN_SDK_NS_GENERAL_STATE_DATA) { + if (message.key == "general.canvas.selection-change") { + // update selection change + const setCrrentSelection = useSetRecoilState( + currentlySelectedPrimaryNodeId + ); + // ... + } + } +} + +/** + * registers handler for remote http(s) call + */ +function registerPluginRemoteCallHandler(message: TransportPluginEvent) { + if (message.namespace == PLUGIN_SDK_NS_REMOTE_API) { + // call remote request + const requestManifest = message.data as NetworkRequest; + Axios.request({ + method: requestManifest.method, + url: requestManifest.url, + data: requestManifest.data, + headers: requestManifest.headers, + }) + .then((r) => { + networkResponseToCodeThread(window, requestManifest.requestId, r.data); + }) + .catch((e) => { + networkResponseToCodeThread(window, requestManifest.requestId, null, e); + }); + } +} + function networkResponseToCodeThread( window: Window, requestId: string, diff --git a/app/lib/utils/plugin-provider/plugin-app-sdk/states/current-node.ts b/app/lib/utils/plugin-provider/pugin-app/states/canvas.ts similarity index 100% rename from app/lib/utils/plugin-provider/plugin-app-sdk/states/current-node.ts rename to app/lib/utils/plugin-provider/pugin-app/states/canvas.ts diff --git a/app/lib/utils/plugin-provider/pugin-app/utils/canvas.ts b/app/lib/utils/plugin-provider/pugin-app/utils/canvas.ts new file mode 100644 index 00000000..c36191a2 --- /dev/null +++ b/app/lib/utils/plugin-provider/pugin-app/utils/canvas.ts @@ -0,0 +1,22 @@ +import { ReflectSceneNode } from "@bridged.xyz/design-sdk/lib/nodes"; + +export function getPrimarySelectedNode(selection: readonly ReflectSceneNode[]) { + // if (){ + // } +} + +export enum SelectionAnalysis { + empty = "empty", + single = "single", + multi = "multi", +} + +export function analyzeSelection(selection: readonly any[]): SelectionAnalysis { + if (selection.length == 0) { + return SelectionAnalysis.empty; + } else if (selection.length == 1) { + return SelectionAnalysis.single; + } else { + return SelectionAnalysis.multi; + } +} diff --git a/app/lib/utils/plugin-provider/pugin-app/utils/index.ts b/app/lib/utils/plugin-provider/pugin-app/utils/index.ts new file mode 100644 index 00000000..df456a37 --- /dev/null +++ b/app/lib/utils/plugin-provider/pugin-app/utils/index.ts @@ -0,0 +1 @@ +export * from "./canvas"; diff --git a/figma/src/code.ts b/figma/src/code.ts index 4bc5db1a..e2034663 100644 --- a/figma/src/code.ts +++ b/figma/src/code.ts @@ -1,7 +1,11 @@ -import { PluginSdkServer } from "app/lib/utils/plugin-provider/plugin-server"; +import { PluginSdkService } from "app/lib/utils/plugin-provider/plugin-service"; import { convertIntoReflectNode } from "@bridged.xyz/design-sdk/lib/nodes/conversion"; import { buildApp } from "core/lib/flutter"; import { retrieveFlutterColors } from "core/lib/flutter/utils/fetch-colors"; +import { + analyzeSelection, + SelectionAnalysis, +} from "app/lib/utils/plugin-provider/pugin-app/utils"; import { hideAllExcept, hideAllOnly, @@ -49,8 +53,6 @@ async function showUI() { figma.showUI(__html__, { width: width, height: height }); } -showUI(); - function delay(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } @@ -169,44 +171,39 @@ async function runon(node: SceneNode) { data: retrieveFlutterColors([convertedSelection]), }); } - figma.on("selectionchange", () => { + // clear the console for better debugging console.clear(); console.warn("log cleared. optimized for new build"); console.log("selection", figma.currentPage.selection); - const selectionCount = figma.currentPage.selection.length; - - // ignore when nothing was selected - if (selectionCount === 0) { - figma.ui.postMessage({ - type: "empty", - }); - return; - } - - // force to single selection - // return false or raise error if more than one node is selected. - if (selectionCount >= 2) { - figma.notify("only single selection is supported", { - timeout: 1.5, - }); - return false; - } - - if (selectionCount === 1) { - const target = figma.currentPage.selection[0]; - figma.ui.postMessage({ - type: "selectionchange", - data: target, - }); - - runon(target); - return; + const selectionType = analyzeSelection(figma.currentPage.selection); + switch (selectionType) { + case SelectionAnalysis.empty: + // ignore when nothing was selected + figma.ui.postMessage({ + type: "empty", + }); + return; + case SelectionAnalysis.multi: + // force to single selection + // return false or raise error if more than one node is selected. + figma.notify("only single selection is supported", { + timeout: 1.5, + }); + return false; + case SelectionAnalysis.single: + const target = figma.currentPage.selection[0]; + figma.ui.postMessage({ + type: "selectionchange", + data: target, + }); + runon(target); + return; } }); -PluginSdkServer.registerDragAndDropHandler( +PluginSdkService.registerDragAndDropHandler( EK_ICON_DRAG_AND_DROPPED, (data, pos): Promise => { createIcon( @@ -225,7 +222,7 @@ PluginSdkServer.registerDragAndDropHandler( figma.ui.onmessage = async (msg) => { console.log("[event] figma plugin data received", msg); - const generalHandlingResult = PluginSdkServer.handle(msg); + const generalHandlingResult = PluginSdkService.handle(msg); // if event is handled by general event handler, no additional handling is required. if (generalHandlingResult) { return; @@ -303,3 +300,9 @@ function hideAllOnlyFromCurrentSelection(only: NodeType) { hideAllOnly(selection, only); } } + +function main() { + showUI(); +} + +main(); diff --git a/packages/lint b/packages/lint index 327d90c9..332ddb0c 160000 --- a/packages/lint +++ b/packages/lint @@ -1 +1 @@ -Subproject commit 327d90c987f65b06b84945d1ba893aa0b7252be7 +Subproject commit 332ddb0c27253359dd638fda5da7356e54a6eadd