From 587fe5cf2aa69e59187e773475ec5127170c98f0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 11:44:53 +0000 Subject: [PATCH 1/4] Initial plan From 239b3044af6bfea0f07a2916cd1ba8a58c74a339 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 11:50:34 +0000 Subject: [PATCH 2/4] move figma-plugin into src/figma-plugin, flatten nested src, update all path references Co-authored-by: abernier <76580+abernier@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- README.md | 2 +- eslint.config.mjs | 7 ++++++- package.json | 2 +- {figma-plugin/src => src/figma-plugin}/code.ts | 2 +- .../src => src/figma-plugin}/constants.ts | 0 {figma-plugin/src => src/figma-plugin}/index.html | 0 {figma-plugin/src => src/figma-plugin}/main.css | 0 {figma-plugin/src => src/figma-plugin}/main.tsx | 14 +++++++------- {figma-plugin => src/figma-plugin}/manifest.json | 0 {figma-plugin => src/figma-plugin}/tsup.config.ts | 4 ++-- {figma-plugin => src/figma-plugin}/vite.config.ts | 4 ++-- tsconfig.json | 2 +- 13 files changed, 22 insertions(+), 17 deletions(-) rename {figma-plugin/src => src/figma-plugin}/code.ts (98%) rename {figma-plugin/src => src/figma-plugin}/constants.ts (100%) rename {figma-plugin/src => src/figma-plugin}/index.html (100%) rename {figma-plugin/src => src/figma-plugin}/main.css (100%) rename {figma-plugin/src => src/figma-plugin}/main.tsx (83%) rename {figma-plugin => src/figma-plugin}/manifest.json (100%) rename {figma-plugin => src/figma-plugin}/tsup.config.ts (69%) rename {figma-plugin => src/figma-plugin}/vite.config.ts (84%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf9ef6b..caa1c73 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,7 +95,7 @@ jobs: set -euo pipefail VERSION="${{ needs.ci.outputs.version }}" - PLUGIN_DIR="figma-plugin" + PLUGIN_DIR="src/figma-plugin" echo "Publishing Figma plugin v${VERSION} (plugin id: ${FIGMA_PLUGIN_ID})" diff --git a/README.md b/README.md index 7751c85..8141492 100644 --- a/README.md +++ b/README.md @@ -455,7 +455,7 @@ $ pnpm i 1. `pnpm run build-figma` 2. In Figma: Plugins → Development → Import plugin from manifest… -3. Select `figma-plugin/manifest.json` +3. Select `src/figma-plugin/manifest.json` ## Validation diff --git a/eslint.config.mjs b/eslint.config.mjs index 73d3f65..694cf56 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -8,7 +8,12 @@ const SOURCE_FILES = ["src/**/*.{ts,tsx}", ".storybook/**/*.{ts,tsx}"]; export default defineConfig([ { - ignores: ["dist/**", "storybook-static/**", "node_modules/**"], + ignores: [ + "dist/**", + "storybook-static/**", + "node_modules/**", + "src/figma-plugin/**", + ], }, { ...reactHooks.configs.flat.recommended, diff --git a/package.json b/package.json index 2560f3e..f82ffad 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "local-release": "pnpm run lgtm && changeset version && changeset publish", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", - "build-figma": "vite build --config figma-plugin/vite.config.ts && tsup --config figma-plugin/tsup.config.ts", + "build-figma": "vite build --config src/figma-plugin/vite.config.ts && tsup --config src/figma-plugin/tsup.config.ts", "chromatic": "chromatic --project-token $CHROMATIC_PROJECT_TOKEN", "prepare": "pnpm run pretest && husky", "changeset": "pnpm exec changeset" diff --git a/figma-plugin/src/code.ts b/src/figma-plugin/code.ts similarity index 98% rename from figma-plugin/src/code.ts rename to src/figma-plugin/code.ts index 53d42f5..03c1294 100644 --- a/figma-plugin/src/code.ts +++ b/src/figma-plugin/code.ts @@ -1,6 +1,6 @@ /// -import type { FigmaVariable } from "../../src/lib/builder"; +import type { FigmaVariable } from "../lib/builder"; import { COLLECTION_NAME } from "./constants"; // ─── Plugin entry point ───────────────────────────────────────────────── diff --git a/figma-plugin/src/constants.ts b/src/figma-plugin/constants.ts similarity index 100% rename from figma-plugin/src/constants.ts rename to src/figma-plugin/constants.ts diff --git a/figma-plugin/src/index.html b/src/figma-plugin/index.html similarity index 100% rename from figma-plugin/src/index.html rename to src/figma-plugin/index.html diff --git a/figma-plugin/src/main.css b/src/figma-plugin/main.css similarity index 100% rename from figma-plugin/src/main.css rename to src/figma-plugin/main.css diff --git a/figma-plugin/src/main.tsx b/src/figma-plugin/main.tsx similarity index 83% rename from figma-plugin/src/main.tsx rename to src/figma-plugin/main.tsx index 22fbeaf..45500b2 100644 --- a/figma-plugin/src/main.tsx +++ b/src/figma-plugin/main.tsx @@ -1,13 +1,13 @@ import { useEffect, useState } from "react"; import { createRoot } from "react-dom/client"; -import { Fab } from "../../src/components/m3/Fab"; -import { FlowfieldSt } from "../../src/Flowfield.stories"; -import { FlowfieldScene } from "../../src/Flowfield.stories.helpers"; -import { Mcu } from "../../src/Mcu"; -import { useMcu } from "../../src/Mcu.context"; +import { Fab } from "../components/m3/Fab"; +import { FlowfieldSt } from "../Flowfield.stories"; +import { FlowfieldScene } from "../Flowfield.stories.helpers"; +import { Mcu } from "../Mcu"; +import { useMcu } from "../Mcu.context"; -import { TooltipProvider } from "../../src/components/ui/tooltip"; -import "../../src/styles/globals.css"; +import { TooltipProvider } from "../components/ui/tooltip"; +import "../styles/globals.css"; import "./main.css"; function SyncButton() { diff --git a/figma-plugin/manifest.json b/src/figma-plugin/manifest.json similarity index 100% rename from figma-plugin/manifest.json rename to src/figma-plugin/manifest.json diff --git a/figma-plugin/tsup.config.ts b/src/figma-plugin/tsup.config.ts similarity index 69% rename from figma-plugin/tsup.config.ts rename to src/figma-plugin/tsup.config.ts index b8673a1..3f37c4e 100644 --- a/figma-plugin/tsup.config.ts +++ b/src/figma-plugin/tsup.config.ts @@ -1,11 +1,11 @@ import { defineConfig } from "tsup"; export default defineConfig({ - entryPoints: ["figma-plugin/src/code.ts"], + entryPoints: ["src/figma-plugin/code.ts"], format: ["iife"], target: "es2015", dts: false, - outDir: "figma-plugin/dist", + outDir: "src/figma-plugin/dist", clean: false, outExtension: () => ({ js: ".js" }), }); diff --git a/figma-plugin/vite.config.ts b/src/figma-plugin/vite.config.ts similarity index 84% rename from figma-plugin/vite.config.ts rename to src/figma-plugin/vite.config.ts index 960fcf4..a166326 100644 --- a/figma-plugin/vite.config.ts +++ b/src/figma-plugin/vite.config.ts @@ -7,11 +7,11 @@ import tsconfigPaths from "vite-tsconfig-paths"; const dir = import.meta.dirname; export default defineConfig({ - root: resolve(dir, "src"), + root: dir, plugins: [ react(), viteSingleFile(), - tsconfigPaths({ root: resolve(dir, "..") }), + tsconfigPaths({ root: resolve(dir, "../..") }), ], build: { outDir: resolve(dir, "dist"), diff --git a/tsconfig.json b/tsconfig.json index 80ee5af..6baaca6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,5 +26,5 @@ "noEmit": true }, "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] + "exclude": ["node_modules", "dist", "src/figma-plugin"] } From 437ebe04d53187715434275af0dfc1ee1fdcd520 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 13:04:28 +0000 Subject: [PATCH 3/4] remove config exclusions, fix pre-existing lint/typecheck issues in figma-plugin code instead Co-authored-by: abernier <76580+abernier@users.noreply.github.com> --- eslint.config.mjs | 7 +---- src/figma-plugin/code.ts | 54 +++++++++++++++++++++++---------------- src/figma-plugin/main.tsx | 1 + tsconfig.json | 2 +- 4 files changed, 35 insertions(+), 29 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 694cf56..73d3f65 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -8,12 +8,7 @@ const SOURCE_FILES = ["src/**/*.{ts,tsx}", ".storybook/**/*.{ts,tsx}"]; export default defineConfig([ { - ignores: [ - "dist/**", - "storybook-static/**", - "node_modules/**", - "src/figma-plugin/**", - ], + ignores: ["dist/**", "storybook-static/**", "node_modules/**"], }, { ...reactHooks.configs.flat.recommended, diff --git a/src/figma-plugin/code.ts b/src/figma-plugin/code.ts index 03c1294..b77d78b 100644 --- a/src/figma-plugin/code.ts +++ b/src/figma-plugin/code.ts @@ -1,6 +1,6 @@ /// -import type { FigmaVariable } from "../lib/builder"; +import type { FigmaVariable, FigmaVariableValue } from "../lib/builder"; import { COLLECTION_NAME } from "./constants"; // ─── Plugin entry point ───────────────────────────────────────────────── @@ -37,14 +37,16 @@ async function findOrCreateCollection(name: string) { function ensureModes(collection: VariableCollection, ...modeNames: string[]) { const result: Record = {}; for (let i = 0; i < modeNames.length; i++) { - const existing = collection.modes.find((m) => m.name === modeNames[i]); + const name = modeNames[i] as string; + const existing = collection.modes.find((m) => m.name === name); if (existing) { - result[modeNames[i]] = existing.modeId; + result[name] = existing.modeId; } else if (i === 0 && collection.modes.length === 1) { - collection.renameMode(collection.modes[0].modeId, modeNames[i]); - result[modeNames[i]] = collection.modes[0].modeId; + const first = collection.modes[0] as { modeId: string; name: string }; + collection.renameMode(first.modeId, name); + result[name] = first.modeId; } else { - result[modeNames[i]] = collection.addMode(modeNames[i]); + result[name] = collection.addMode(name); } } return result; @@ -64,6 +66,28 @@ async function findOrCreateVariable( // ─── Sync logic ───────────────────────────────────────────────────────── +function setModeValue( + variable: Variable, + modeId: string, + value: FigmaVariableValue, + varMap: Record, +) { + if ("alias" in value) { + const target = varMap[value.alias]; + if (target) { + variable.setValueForMode( + modeId, + figma.variables.createVariableAlias(target), + ); + } else { + console.warn(`Alias target not found: ${value.alias}`); + variable.setValueForMode(modeId, { r: 0, g: 0, b: 0, a: 1 }); + } + } else { + variable.setValueForMode(modeId, value); + } +} + async function syncVariables(variables: FigmaVariable[]) { const collection = await findOrCreateCollection(COLLECTION_NAME); const modes = ensureModes(collection, "Light", "Dark"); @@ -77,28 +101,14 @@ async function syncVariables(variables: FigmaVariable[]) { // Set values and metadata for (const v of variables) { const variable = varMap[v.path]; + if (!variable) continue; if (v.description) variable.description = v.description; if (v.scopes) variable.scopes = v.scopes as VariableScope[]; for (const [modeName, modeId] of Object.entries(modes)) { const value = v.values[modeName]; - if (!value) continue; - - if ("alias" in value) { - const target = varMap[value.alias]; - if (target) { - variable.setValueForMode( - modeId, - figma.variables.createVariableAlias(target), - ); - } else { - console.warn(`Alias target not found: ${value.alias}`); - variable.setValueForMode(modeId, { r: 0, g: 0, b: 0, a: 1 }); - } - } else { - variable.setValueForMode(modeId, value); - } + if (value) setModeValue(variable, modeId, value, varMap); } } diff --git a/src/figma-plugin/main.tsx b/src/figma-plugin/main.tsx index 45500b2..4b709f8 100644 --- a/src/figma-plugin/main.tsx +++ b/src/figma-plugin/main.tsx @@ -73,4 +73,5 @@ function App() { ); } +// eslint-disable-next-line @typescript-eslint/no-non-null-assertion createRoot(document.getElementById("root")!).render(); diff --git a/tsconfig.json b/tsconfig.json index 6baaca6..80ee5af 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,5 +26,5 @@ "noEmit": true }, "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "src/figma-plugin"] + "exclude": ["node_modules", "dist"] } From ca714d99c83925de3b29774d2dff27abcc91f0a3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 13:06:25 +0000 Subject: [PATCH 4/4] replace type assertions with proper null guards per code review Co-authored-by: abernier <76580+abernier@users.noreply.github.com> --- src/figma-plugin/code.ts | 6 ++++-- src/figma-plugin/main.tsx | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/figma-plugin/code.ts b/src/figma-plugin/code.ts index b77d78b..9f9aa0e 100644 --- a/src/figma-plugin/code.ts +++ b/src/figma-plugin/code.ts @@ -37,12 +37,14 @@ async function findOrCreateCollection(name: string) { function ensureModes(collection: VariableCollection, ...modeNames: string[]) { const result: Record = {}; for (let i = 0; i < modeNames.length; i++) { - const name = modeNames[i] as string; + const name = modeNames[i]; + if (!name) continue; const existing = collection.modes.find((m) => m.name === name); if (existing) { result[name] = existing.modeId; } else if (i === 0 && collection.modes.length === 1) { - const first = collection.modes[0] as { modeId: string; name: string }; + const first = collection.modes[0]; + if (!first) continue; collection.renameMode(first.modeId, name); result[name] = first.modeId; } else { diff --git a/src/figma-plugin/main.tsx b/src/figma-plugin/main.tsx index 4b709f8..f695310 100644 --- a/src/figma-plugin/main.tsx +++ b/src/figma-plugin/main.tsx @@ -73,5 +73,5 @@ function App() { ); } -// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -createRoot(document.getElementById("root")!).render(); +const root = document.getElementById("root"); +if (root) createRoot(root).render();