diff --git a/.github/workflows/code-connect.yml b/.github/workflows/code-connect.yml new file mode 100644 index 000000000..3d5f13447 --- /dev/null +++ b/.github/workflows/code-connect.yml @@ -0,0 +1,90 @@ +name: 'Figma Code Connect' + +# Keeps the Figma Code Connect mappings (libs/figma/*.figma.ts) in sync with +# Figma. Previously this was only ever run by hand — `@figma/code-connect` isn't +# even a declared dependency — so Dev Mode was only as fresh as the last person +# who remembered to run `figma connect publish` locally with a personal token. +# +# - On PRs touching the mappings: `parse` (validate every file locally, no +# token, no publish) so a broken mapping fails the PR instead of silently +# shipping stale code snippets. +# - On merge to main (or manual dispatch): `publish` the mappings to Figma so +# each connected component emits its `pds-*` example in Dev Mode. + +on: + pull_request: + branches: ['**'] + paths: + - 'libs/figma/**' + - 'figma.config.json' + - '.github/workflows/code-connect.yml' + push: + branches: [main] + paths: + - 'libs/figma/**' + - 'figma.config.json' + - '.github/workflows/code-connect.yml' + workflow_dispatch: + +concurrency: + group: code-connect-${{ github.ref }} + cancel-in-progress: true + +env: + # Bump to upgrade the Code Connect CLI. Kept as an npx pin (not a package.json + # dependency) so this workflow stays self-contained and matches how the CLI is + # run today; promote to a pinned devDependency if it ever needs to run inside + # the normal build/lint pipeline. + # + # Minimum 1.4.4: `--exit-on-unreadable-files` is only respected for .figma.ts / + # .figma.js templates (our parser is `html`) from 1.4.4 onward. Below that the + # flag is a no-op and an unparseable mapping is silently skipped — the exact + # green-but-stale failure this workflow guards against. + CODE_CONNECT_VERSION: '1.5.3' + +jobs: + # PR gate: parse the *.figma.ts files against figma.config.json. Local only — + # no Figma access, no token — so it's safe to run on forks and validates that + # every mapping still compiles and resolves its imports/substitutions. + validate: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - name: Set up Node.js (pinned npm) + uses: ./.github/workflows/actions/setup-node-with-pinned-npm + with: + node-version-file: '.nvmrc' + - name: Parse Code Connect files (validate, no publish) + shell: bash + # --exit-on-unreadable-files: fail instead of silently skipping a file the + # CLI can't parse — otherwise a broken mapping passes the gate green. + run: npx -y --package=@figma/code-connect@${CODE_CONNECT_VERSION} figma connect parse --exit-on-unreadable-files + + # Publish on merge to main or manual dispatch. Requires the FIGMA_ACCESS_TOKEN + # secret (a Figma personal access token with Code Connect write scope). + publish: + if: github.event_name != 'pull_request' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - name: Set up Node.js (pinned npm) + uses: ./.github/workflows/actions/setup-node-with-pinned-npm + with: + node-version-file: '.nvmrc' + - name: Guard — require FIGMA_ACCESS_TOKEN + shell: bash + env: + FIGMA_ACCESS_TOKEN: ${{ secrets.FIGMA_ACCESS_TOKEN }} + run: | + if [ -z "${FIGMA_ACCESS_TOKEN}" ]; then + echo "::error::FIGMA_ACCESS_TOKEN secret is not set — cannot publish Code Connect. Add a Figma personal access token (Code Connect write scope) under repo Settings → Secrets and variables → Actions." + exit 1 + fi + - name: Publish Code Connect to Figma + shell: bash + env: + FIGMA_ACCESS_TOKEN: ${{ secrets.FIGMA_ACCESS_TOKEN }} + # --exit-on-unreadable-files: fail the publish rather than shipping a + # partial set and leaving stale Dev Mode snippets for the skipped files. + run: npx -y --package=@figma/code-connect@${CODE_CONNECT_VERSION} figma connect publish --exit-on-unreadable-files diff --git a/libs/figma/CODE_CONNECT_COVERAGE.md b/libs/figma/CODE_CONNECT_COVERAGE.md index 11f88657b..8048e9a66 100644 --- a/libs/figma/CODE_CONNECT_COVERAGE.md +++ b/libs/figma/CODE_CONNECT_COVERAGE.md @@ -2,6 +2,15 @@ This file tracks which Pine `pds-*` components have a matching Code Connect file under `libs/figma/`. Update this list when you add or remove mappings. +## How mappings reach Figma + +The `.figma.ts` files are published to Figma by the **Figma Code Connect** workflow (`.github/workflows/code-connect.yml`): + +- **PRs** touching `libs/figma/**` or `figma.config.json` run `figma connect parse` — a local validation that every mapping compiles and resolves, no token, no publish. +- **Merges to `main`** (and manual dispatch) run `figma connect publish`, which requires the `FIGMA_ACCESS_TOKEN` secret (a Figma PAT with Code Connect write scope). + +Before this workflow, publishing was a manual, undocumented local step — Dev Mode was only as fresh as the last person who remembered to run it. + ## Mapped (Code Connect present) | Pine component / pattern | Code Connect file | @@ -37,7 +46,6 @@ Use `figma.config.json` at the repo root (`documentUrlSubstitutions`) when addin | Pine component | Notes | | --- | --- | | `pds-accordion` | Add `components/pds-accordion.figma.ts` when the Figma node is ready. | -| `pds-box` | Layout primitive; may map to layout frames rather than a single component node. | | `pds-combobox` | | | `pds-container` | | | `pds-copytext` | | @@ -49,5 +57,13 @@ Use `figma.config.json` at the repo root (`documentUrlSubstitutions`) when addin | `pds-row` | Often used with `pds-box`; may share layout documentation. | | `pds-sortable` | Figma substitutions exist for sortable list patterns; wire a `pds-sortable.figma.ts` when aligned. | | `pds-table` | Composite; consider per-subcomponent mappings (row, cell, head) if needed. | -| `pds-text` | | | `pds-tooltip` | | + +## Primitives — not Code-Connectable (no component node) + +`pds-box` and `pds-text` **cannot** take a `.figma.ts` file: Code Connect's `figma.connect()` attaches to a Figma **component node**, and neither exists as one in the Pine Figma file: + +- **`pds-text`** — text is represented by **text styles** (`✳ Pine styles`: `typography/heading/1..6`, `typography/body`, `typography/body-sm`, …), not a "Text" component. +- **`pds-box`** — layout is **auto-layout + bound spacing/radius variables**, not a "Box"/"Stack"/"Container" component. + +Their relationship to code is instead carried as a **style/variable → code map** in the `pine-figma` authoring skill (`skills/pine-figma/reference/primitives.md`): text-style → `pds-text` and auto-layout → `pds-box`. Do not open Code Connect files for these — there is no node to bind to.