Skip to content

Commit

Permalink
Merge branch 'main' into fix/2331-custom-angle-linear-gradients
Browse files Browse the repository at this point in the history
  • Loading branch information
macintoshhelper authored Nov 14, 2024
2 parents a7c5661 + 6fd921c commit 5589616
Show file tree
Hide file tree
Showing 60 changed files with 1,542 additions and 154 deletions.
5 changes: 5 additions & 0 deletions .changeset/healthy-rabbits-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tokens-studio/figma-plugin": patch
---

fixed an issue with pulling token sets from Bitbucket when multi-file sync is enabled, wherein all the token sets were not being pulled.
5 changes: 0 additions & 5 deletions .changeset/heavy-colts-look.md

This file was deleted.

5 changes: 5 additions & 0 deletions .changeset/old-pots-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tokens-studio/figma-plugin": patch
---

Disable cache for Bitbucket
5 changes: 0 additions & 5 deletions .changeset/perfect-fishes-smoke.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/twenty-days-relate.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/weak-oranges-buy.md

This file was deleted.

147 changes: 147 additions & 0 deletions developer-knowledgebase/async-message-channel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# AsyncMessageChannel

## `AsyncMessageChannel` Data Flow

```mermaid
graph TD
A["Figma Plugin Controller\n(Sandbox Env)\ncontroller.ts"]
B[AsyncMessageChannel\nPluginInstance\nEnvironment.CONTROLLER]
C[Figma Plugin UI\nUI entrypoint\napp/index.tsx]
D[AsyncMessageChannel\nReactInstance\nEnvironment.UI]
E[Web Browser Preview\nhttp://localhost:9000]
F[AsyncMessageChannel\nReactInstance\nEnvironment.BROWSER]
A -->|"PluginInstance.connect()"| B
B -->|"PluginInstance.handle(...)"| A
B -->|"ReactInstance.connect()"| C
C -->|"ReactInstance.handle(...)"| B
C -->|"sendMessageToUi\n(figma.ui.postMessage(...))"| D
D -->|"sendMessageToController\n(parent.postMessage({ pluginMessage: {...} }))"| C
D -->|"ReactInstance.connect()"| E
E -->|"ReactInstance.handle(...)"| D
E -->|"sendMessageToBrowser\n(ws.send(...))"| F
F -->|"sendMessageFromBrowser\n(ws.send(...))"| E
```

## Instances

Static instances of `AsyncMessageChannel` are initialised when the class is loaded:

- `PluginInstance` - used from inside of `controller` entrypoint
- `ReactInstance` - used from inside of `ui` entrypoint

```ts
class AsyncMessageChannel {
public static PluginInstance: AsyncMessageChannel = new AsyncMessageChannel(true);
public static ReactInstance: AsyncMessageChannel = new AsyncMessageChannel(false);

protected inFigmaSandbox = false;

constructor(inFigmaSandbox: boolean) {
this.inFigmaSandbox = inFigmaSandbox
}
}

```

-

## Environments

There are currently three environments:

```ts
enum Environment {
PLUGIN = 'PLUGIN',
UI = 'UI',
BROWSER = 'BROWSER',
```
- `Environment.PLUGIN``controller` entrypoint
- `Environment.UI``ui` entrypoint
- Has access to `parent.postMessage`
- `Environment.BROWSER``ui` entrypoint
- Need to use WebSockets to send messages to the plugin `ui`
## Lifecycle
**`.connect()`**
Example: `AsyncMessageChannel.PluginInstance.connect();` or `AsyncMessageChannel.ReactInstance.connect();`
If in a web preview environment (`Environment.BROWSER` or `Environment.UI`), a WebSocket client listener is registered here (`this.startWebSocketConnection();`)
Registers message listeners with `this.attachMessageListener(callback)`, where `callback` in this case is [`this.onMessageEvent`](#onmessageeventmsg)
**`.attachMessageListener(callback)`**
Conditionally registers message event handlers depending on the environment:
- `Environment.CONTROLLER`
- `figma.ui.on('message', listener)`
- `Environment.UI`
- `window.addEventListener('message', listener)` – listens to messages controller
- *IF process.env.PREVIEW_MODE IS SET*
- `this.ws?.addEventListener('message', listener)`
- Where if this condition is true, `UI` has two message listeners, one to listen
- `Environment.CONTROLLER`
- `this.ws?.addEventListener('message', listener)`

Where `listener` is a function that is wrapping `callback`:

### `.onMessageEvent(msg)`

If the environment is preview, and message is not async, the UI environment will forward the message to the browser. Else, non async messages are discarded with `return;`

Next, if the environment is `UI` and `PREVIEW_MODE` is truthy, the message is forwarded via WebSockets to the browser, or to the controller.

Then the handler is called; the function is retrieved from `$handlers[msg.message.type]`.

The result of the handler function is `await`ed and a message is sent back to the source with the same message type, and the payload from the handler function result.

## Message Handling

`AsyncMessageChannel` handles messages with `.message` to send messages and receives messages (say in a different instance) by registering a handler with `.handle()`. Each handler is stored in the class/instance in `$handlers`, keyed by the message type.

Example: `AsyncMessageChannel.ReactInstance.handle(AsyncMessageTypes.STARTUP, asyncHandlers.startup)`.

### Startup Process

**`controller.ts`**

```ts
AsyncMessageChannel.PluginInstance.connect();
```


**`init.ts`**

```ts
// Creating the plugin UI instance (AsyncMessageChannel.ReactInstance)
figma.showUI(__html__, {
themeColors: true,
width: params.settings.width ?? DefaultWindowSize.width,
height: params.settings.height ?? DefaultWindowSize.height,
});
//
await AsyncMessageChannel.PluginInstance.message({
type: AsyncMessageTypes.STARTUP,
...params,
});
```

**`asyncMessageHandlers/startup.tsx` / `StartupApp`**

```tsx
useEffect(() => {
AsyncMessageChannel.ReactInstance.handle(AsyncMessageTypes.STARTUP, async (startupParams) => {
setParams(startupParams);
});
return () => {
AsyncMessageChannel.ReactInstance.handle(AsyncMessageTypes.STARTUP, (() => {}) as any);
};
}, []);
```

11 changes: 11 additions & 0 deletions developer-knowledgebase/web-preview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Web Preview

## Getting Started

1. Open Terminal and run:

> Terminal
```sh
npm run preview
```
13 changes: 13 additions & 0 deletions packages/tokens-studio-for-figma/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# @tokens-studio/figma-plugin

## 2.2.0

### Minor Changes

- da1886da: Re-introduces "Update styles". If enabled, the plugin will update any local styles when token values or themes change. By default, this setting is off. It's available from the gear menu in the bottom right

### Patch Changes

- 80a5a92b: Fixed an issue where sometimes duplicate sync providers would show up
- 4fd3f9b1: fix(tokenState): setTokensFromVariables description comparison
- 7be0b29d: Fixed an issue where referencing a gradient would result in an empty color style; now the style correctly resolves to the gradient.
- a6eb07de: fixes a bug where applying a typography token to a text node would override individual property changes (like font size or font family) when "Apply to selection/page/document" is clicked.

## 2.1.1

### Patch Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('Branch switcher', () => {
updateMode: UpdateMode.PAGE,
updateOnChange: false,
updateRemote: true,
updateStyles: true,
shouldUpdateStyles: true,
},
storageType: provider,
user: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('Inspector tokens', () => {
updateMode: UpdateMode.PAGE,
updateOnChange: false,
updateRemote: true,
updateStyles: true,
shouldUpdateStyles: true,
},
storageType: { provider: StorageProviderType.LOCAL },
user: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('TokenListing', () => {
updateMode: UpdateMode.PAGE,
updateOnChange: false,
updateRemote: true,
updateStyles: true,
shouldUpdateStyles: true,
},
storageType: { provider: StorageProviderType.LOCAL },
user: {
Expand Down
2 changes: 1 addition & 1 deletion packages/tokens-studio-for-figma/cypress/e2e/startup.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('Loads application', () => {
updateMode: UpdateMode.PAGE,
updateOnChange: false,
updateRemote: true,
updateStyles: true,
shouldUpdateStyles: true,
},
storageType: { provider: StorageProviderType.LOCAL },
user: {
Expand Down
2 changes: 1 addition & 1 deletion packages/tokens-studio-for-figma/cypress/e2e/themes.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('Themes', () => {
updateMode: UpdateMode.PAGE,
updateOnChange: false,
updateRemote: true,
updateStyles: true,
shouldUpdateStyles: true,
},
storageType: { provider: StorageProviderType.LOCAL },
user: {
Expand Down
2 changes: 1 addition & 1 deletion packages/tokens-studio-for-figma/cypress/e2e/tokens.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('TokenListing', () => {
updateMode: UpdateMode.PAGE,
updateOnChange: false,
updateRemote: true,
updateStyles: true,
shouldUpdateStyles: true,
},
storageType: { provider: StorageProviderType.LOCAL },
user: {
Expand Down
17 changes: 15 additions & 2 deletions packages/tokens-studio-for-figma/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tokens-studio/figma-plugin",
"version": "2.1.1",
"version": "2.2.0",
"description": "Tokens Studio plugin for Figma",
"license": "MIT",
"private": true,
Expand All @@ -9,8 +9,13 @@
"watch-transform": "webpack --mode=development --watch --config webpack-transform.config.js",
"build": "cross-env NODE_ENV=production webpack --mode=production",
"build:dev": "cross-env NODE_ENV=development webpack --mode=development",
"build:preview": "cross-env NODE_ENV=development webpack --mode=development --PREVIEW_ENV=browser",
"build:cy": "cross-env LAUNCHDARKLY_FLAGS=tokenThemes,gitBranchSelector,multiFileSync,tokenFlowButton yarn build",
"start": "cross-env webpack --mode=development --watch",
"preview:ws": "node preview-server.js",
"preview:plugin": "webpack --mode=development --PREVIEW_ENV=figma",
"preview:browser": "webpack-dev-server --mode=development --PREVIEW_ENV=browser",
"preview": "cross-env WEBSOCKETS_PORT=9001 run-p \"preview:*\"",
"build-transform": "webpack --mode=production --config webpack-transform.config.js",
"benchmark:build": "webpack --config webpack-benchmark.config.js",
"benchmark:run": "node benchmark/index.mjs",
Expand All @@ -24,6 +29,7 @@
"cy:open": "cypress open",
"cy:run": "cypress run --headless",
"serve": "serve dist -p 58630",
"serve:preview": "serve preview -p 58630",
"changeset": "changeset",
"translate": "node ./scripts/translate.mjs",
"lint": "eslint . --quiet --fix",
Expand Down Expand Up @@ -146,6 +152,7 @@
"@babel/preset-typescript": "^7.12.16",
"@changesets/cli": "^2.26.2",
"@figma/plugin-typings": "^1.96.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.13",
"@sentry/webpack-plugin": "^2.2.0",
"@storybook/addon-actions": "^6.5.8",
"@storybook/addon-docs": "^6.5.8",
Expand Down Expand Up @@ -200,10 +207,11 @@
"eslint-plugin-react": "^7.27.1",
"eslint-plugin-react-hooks": "^4.4.0",
"eslint-plugin-validate-jsx-nesting": "^0.1.1",
"express": "^4.19.2",
"figma-api-stub": "^0.0.56",
"figma-plugin-ds": "^1.0.1",
"file-loader": "^6.2.0",
"fork-ts-checker-webpack-plugin": "^7.2.11",
"fork-ts-checker-webpack-plugin": "7.2.11",
"fs-extra": "^11.1.1",
"html-inline-script-webpack-plugin": "^3.2.0",
"html-webpack-plugin": "^5.0.0",
Expand All @@ -218,22 +226,27 @@
"postcss-cli": "^8.3.1",
"prettier": "^2.0.5",
"react-devtools": "^4.28.4",
"react-refresh-typescript": "^2.0.9",
"react-svg-loader": "^3.0.3",
"react-test-renderer": "17.0.0",
"round-to": "^6.0.0",
"serve": "^11.3.2",
"speed-measure-webpack-plugin": "^1.5.0",
"style-loader": "^3.3.2",
"svg-url-loader": "^7.1.1",
"swc-loader": "^0.2.3",
"translate": "^2.0.2",
"ts-jest": "^29.1.1",
"ts-loader": "^9.5.1",
"ts-node": "^10.8.1",
"tslint": "^5.18.0",
"tslint-react": "^4.0.0",
"typescript": "~4.7.4",
"url-loader": "^2.1.0",
"webpack": "5",
"webpack-bundle-analyzer": "^4.10.2",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "3.x",
"whatwg-fetch": "^3.6.2"
},
"husky": {
Expand Down
44 changes: 44 additions & 0 deletions packages/tokens-studio-for-figma/preview-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const express = require('express');
const http = require('http');
const WebSocket = require('ws');

const PORT = process.env.WEBSOCKETS_PORT || 9001;

const app = express();

app.use(express.static(__dirname + '/dist'));

app.get('/', (req, res) => {
res.status(200).send('working');
});

const server = http.createServer(app);

const wss = new WebSocket.Server({ server });
wss.on('connection', (ws) => {
ws.isAlive = true;
ws.on('pong', () => {
ws.isAlive = true;
});

ws.on('message', (data, isBinary) => {
const message = isBinary ? data : data.toString();
wss.clients.forEach((client) => {
if (client != ws) {
client.send(JSON.stringify({ message, src: 'server' }));
}
});
});
});

setInterval(() => {
wss.clients.forEach((ws) => {
if (!ws.isAlive) return ws.terminate();
ws.isAlive = false;
ws.ping();
});
}, 10000);

server.listen(PORT, () => {
console.log(`Preview server started on port: ${PORT}`);
});
Loading

0 comments on commit 5589616

Please sign in to comment.