Skip to content

Commit

Permalink
Code Connect v1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
figma-bot committed Jun 19, 2024
1 parent 3388b6c commit 622b705
Show file tree
Hide file tree
Showing 47 changed files with 937 additions and 496 deletions.
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
# Code Connect v1.0.0 (19th June 2024)

## Features

### General
- Added [documentUrlSubstitutions](README.md#documenturlsubstitutions) config option

### Jetpack Compose
- Added support for Android Jetpack Compose. See the [README](compose/README.md) to get started

### React
- Interactive setup flow, launched by running `figma connect`, which guides you through the setup process and auto-connects your components

## Fixed

### General
- Automatic config migration (added in v0.2.0) now correctly preserves `include`/`exclude` config options
- Icon script helpers moved to a named export so they can be imported correctly (see [README](cli/scripts/README.md))

### React
- Nested helpers within `figma.nestedProps` now work as expected
- Props can now be rendered in nested object props

### SwiftUI
- `create` now outputs Swift files with the correct syntax

# Code Connect v0.2.1 (17th June 2024)

## Fixed
Expand Down
39 changes: 34 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

Code Connect is a tool for connecting your design system components in code with your design system in Figma. When using Code Connect, Figma's Dev Mode will display true-to-production code snippets from your design system instead of autogenerated code examples. In addition to connecting component definitions, Code Connect also supports mapping properties from code to Figma enabling dynamic and correct examples. This can be useful for when you have an existing design system and are looking to drive consistent and correct adoption of that design system across design and engineering.

Code Connect is easy to set up, easy to maintain, type-safe, and extensible. Out of the box Code Connect comes with support for React, Storybook and SwiftUI.
Code Connect is easy to set up, easy to maintain, type-safe, and extensible. Out of the box Code Connect comes with support for React (and React Native), Storybook, SwiftUI and Jetpack Compose.

![image](https://static.figma.com/uploads/9a04c8236ff9cc18303b98a0983c82a589b6cfe3.png)
![image](https://static.figma.com/uploads/d98e747613e01685d6a0f9dd3e2dcd022ff289c0.png)

> [!NOTE]
> Code Connect is available on Organization and Enterprise plans and requires a full Design or Dev Mode seat to use. Code Connect is currently in beta, so you can expect this feature to change. You may also experience bugs or performance issues during this time.
Expand All @@ -25,8 +25,9 @@ We hope to provide a way to install Code Connect without requiring Node.js soon.

To learn how to implement Code Connect for your platform, please navigate to the platform-specific API usage and documentation.

- [React](cli/README.md)
- [React (or React Native)](cli/README.md)
- [SwiftUI](swiftui/README.md)
- [Jetpack Compose](compose/README.md)

## General configuration

Expand All @@ -36,7 +37,7 @@ Every platform supports some common configuration options, in addition to any pl

### `include` and `exclude`

`include` and `exclude` are lists of globs for where to parse Code Connect files. `include` and `exclude` paths must be relative to the location of the config file.
`include` and `exclude` are lists of globs for where to parse Code Connect files, and for where to search for your component code when using the [interactive setup](cli/README.md#interactive-setup). `include` and `exclude` paths must be relative to the location of the config file.

```jsonp
{
Expand All @@ -50,10 +51,12 @@ Every platform supports some common configuration options, in addition to any pl
### `parser`

Code Connect will attempt to determine your project type by looking the first ancestor of the working directory which matches one of the following:

- If a `package.json` containing `react` is found, your project is detected as React
- If a file matching `Package.swift` or `*.xcodeproj` is found, your project is detected as Swift
- If a file matching `build.gradle.kts` is found, your project is detected as Jetpack Compose

In case this does not correctly work for your project, you can override the project type by using the `parser` configuration key. Valid values are `react` or `swift`.
In case this does not correctly work for your project, you can override the project type by using the `parser` configuration key. Valid values are `react`, `swift` and `compose`.

```jsonp
{
Expand All @@ -62,3 +65,29 @@ In case this does not correctly work for your project, you can override the proj
}
}
```

### `documentUrlSubstitutions`

`documentUrlSubstitutions` allows you to specify a set of substitutions which will be run on the `figmaNode` URLs when parsing or publishing documents.

This allows you to use different config files to switch publishing Code Connect between different files, without having to modify every Code Connect file (e.g. if you have a test version of your document you want to publish to). The substitutions are specified as an object, where the key is the string to be replaced, and the value is the string to replace that with.

For example, the config:

```
{
"codeConnect": {
"documentUrlSubstitutions": {
"https://figma.com/design/1234abcd/File-1": "https://figma.com/design/5678dcba/File-2"
}
}
}
```

would change Figma node URLs like `https://figma.com/design/1234abcd/File-1/?node-id=12:345` to `https://figma.com/design/5678dbca/File-2/?node-id=12:345`.

## Common issues

### Connectivity issues due to proxies or network security software

Some proxies or network security software can prevent Code Connect from communicating with Figma's servers. If you encounter issues, you may need to explicitly allow connections to `https://api.figma.com/`. Please reach out to [Figma support](https://help.figma.com/hc/en-us/requests/new) if you are still unable to use Code Connect.
18 changes: 13 additions & 5 deletions cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

For more information about Code Connect as well as guides for other platforms and frameworks, please [go here](../README.md).

This documentation will help you connect your React components with Figma components using Code Connect. We'll cover basic setup to display your first connected code snippet, followed by making snippets dynamic by using property mappings. Code Connect for React works as both a standalone implementation and as an integration with existing Storybook files to enable easily maintaining both systems in parallel.
This documentation will help you connect your React (or React Native) components with Figma components using Code Connect. We'll cover basic setup to display your first connected code snippet, followed by making snippets dynamic by using property mappings. Code Connect for React works as both a standalone implementation and as an integration with existing Storybook files to enable easily maintaining both systems in parallel.

## Installation

Expand Down Expand Up @@ -48,6 +48,16 @@ Now go back to Dev Mode in Figma and select the component that you just connecte
> [!NOTE]
> Code Connect files are not executed. While they're written using real components from your codebase, the Figma CLI essentially treats code snippets as strings. This means you can use, for example, hooks without needing to mock data. However, this also means that logical operators such as ternaries or conditionals will be output verbatim in your example code rather than executed to show the result. You also won't be able to dynamically construct `figma.connect` calls in a for-loop, as an example. If something you're trying to do is not possible because of this restriction in the API, we'd love to hear your feedback.
## Interactive setup

A step-by-step interactive flow is provided which makes it easier to connect a large codebase. Code Connect will attempt to automatically connect your codebase to your Figma design system components based on name, which you can then make any edits to before batch-creating Code Connect files.

To start the interactive setup, enter `figma connect` without any subcommands:

```sh
npx figma connect
```

## Integrating with Storybook

If you already have Storybook set up for your design system then we recommend using the Storybook integration that comes with Code Connect. Storybook and Code Connect complement each other nicely and with this integration they are easy to maintain in parallel. The syntax for integrating with Storybook is slightly different to ensure alignment with the Storybook API.
Expand Down Expand Up @@ -291,7 +301,7 @@ figma.boolean('Has Icon', {
### Enums
Variants (or enums) in Figma are commonly used to control the look and feel of components that require more complex options than a simple boolean toggle. Variant properties are always strings in Figma but they can be mapped to any type in code.
Variants (or enums) in Figma are commonly used to control the look and feel of components that require more complex options than a simple boolean toggle. Variant properties are always strings in Figma but they can be mapped to any type in code. The first parameter is the name of the Variant in Figma, and the second parameter is a value mapping. The _keys_ in this object should match the different options of that Variant in Figma, and the _value_ is whatever you want to output instead.
```tsx
// maps the 'Options' variant in Figma to enum values in code
Expand Down Expand Up @@ -388,9 +398,7 @@ figma.children('Icon*')
### Nested properties
In cases where you don't want to connect a child component, but instead map its properties on the parent level, you can use
`figma.nestedProps()` to achieve this. This helper takes the name of the layer as it's first parameter (similar to `figma.children`),
and a mapping object as the second parameter. These props can then be referenced in the example function.
In cases where you don't want to connect a child component, but instead map its properties on the parent level, you can use `figma.nestedProps()` to achieve this. This helper takes the name of the layer as it's first parameter, and a mapping object as the second parameter. These props can then be referenced in the example function. `nestedProps` will always select a **single** instance, and cannot be used to map multiple children.
```tsx
// map the properties of a nested instance named "Button Shape"
Expand Down
2 changes: 1 addition & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@figma/code-connect",
"version": "0.2.1",
"version": "1.0.0",
"description": "A tool for connecting your design system components in code with your design system in Figma",
"keywords": [],
"author": "Figma",
Expand Down
96 changes: 39 additions & 57 deletions cli/scripts/README.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,59 @@
# Code Connect for icons

`import-icons.ts` is a node script that uses the [Figma API](https://www.figma.com/developers/api) to pull icons from a Figma file and generate a Code Connect file for your icons. This template is meant to be used as a starting point - some parts will need to be edited to work with your design system and code base. These areas are marked with "EDIT THIS" in the file.
This folder includes example scripts for generating Code Connect files for your components. This is useful for icons, where you might have tons of icons that you don't want to manually connect one by one.

## Usage

Run the script with e.g `npx tsx`:
To run the scripts, you'll need to set the `FIGMA_ACCESS_TOKEN` env variable. [See here](https://www.figma.com/developers/api#access-tokens) for how to get this token.

Run the scripts with e.g `npx tsx`:
```
FIGMA_ACCESS_TOKEN=<my token> npx tsx import-icons.ts
```

## Modifying the script

There are many ways your icons can be setup in Figma and in code. This base template assumes that:
* Your icons in Figma include the string "icon" in the name
* Your icon components in code are named similarly and include the size, e.g `Icon32Search`

Here are some examples of how you can modify the script to work with your setup.

### Icons with size as a prop

If your icons in Figma has properties/variants for size, you can modify the script to handle this.

Change the `generateCodeConnectIcons` function:
or, if you have the access token in an `.env` file, Code Connect will pick that up:
```
npx tsx import-icons.ts
```

```ts
// ...
## Code Connect Client

let name = figmaName
.split(/[.-]/g)
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
.join('')
`client` includes helper functions for interacting with Figma files and generating Code Connect files. It uses the [Figma REST API](https://www.figma.com/developers/api) under the hood. This folder includes a few example scripts that can be modified to fit your needs.

// added line: remove the size from the component name
name = name.replace(/[0-9]+/g, '')
`getComponents` will fetch any components in a file, or if a node-id query parameter is provided, any nodes within that frame. The result can then be used to dynamically connect components with `figma.connect()` and write this to a file that can be published with `figma connect publish`.

// added line: extract the size from the figma name.
// default to 16 if no size specified in the Figma name
const [_match, size] = figmaName.match(/([0-9]+)/) ?? [null, '16']
```
import { client } from '@figma/code-connect'
const info: IconInfo = {
id,
name,
figmaName,
figmaUrl,
size,
async function getIcons() {
const components = await client.getComponents('https://figma.com/file/ABc123IjkLmnOPq?node-id=41-41')
const icons = components.filter(({ name }) => name.startsWith('icon'))
// ... write code connect file
}
icons.push(info)

// ...
```

Change the `writeCodeConnectFile` function to include an `example` that passes the size to your icon component:
`getComponents` returns an array of `Component` objects with the following type:

```ts
async function writeCodeConnectFile(dir: string, icons: IconInfo[]) {
const uniqueNames = new Set([...icons.map((icon) => icon.name)])
fs.writeFileSync(
path.join(dir, ICONS_CODE_CONNECT_FILE),
`\
import figma from '@figma/code-connect'
import {
${Array.from(uniqueNames)
.map((iconName) => ` ${iconName},`)
.join('\n')}
} from '${ICONS_IMPORT_PATH}'
${icons
.map(
(icon) => `figma.connect(${icon.name}, '${icon.figmaUrl}', {
example: () => <${icon.name} size={${icon.size}} />,
})`,
)
.join('\n')}
`,
)
```
interface Component {
// the type of component (only COMPONENT_SET nodes can have variant properties)
type: 'COMPONENT' | 'COMPONENT_SET'
// the name of the component in Figma
name: string
// a unique ID for this node
id: string
// file key for the file containing this node
fileKey: string
// URL to this node
figmaUrl: string
// Properties for this component, keyed by the name of the property
componentPropertyDefinitions: Record<string, {
defaultValue: boolean | string
type: 'BOOLEAN' | 'INSTANCE_SWAP' | 'TEXT' | 'VARIANT'
// All possible values for this property. Only exists on VARIANT properties
variantOptions?: string[]
}>
}
```

58 changes: 58 additions & 0 deletions cli/scripts/import-icons-size-prop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// change to: "import { client } from '@figma/code-connect'"
import { client } from '../src'
import fs from 'fs'
import path from 'path'

async function generateIconsWithSizeProp() {
// fetch components from a figma file. If the `node-id` query parameter is used,
// only components within those frames will be included. This is useful if your
// file is very large, as this will speed up the query by a lot
let components = await client.getComponents(
'https://figma.com/file/ABc123IjkLmnOPq?node-id=41-41',
)

// Map from figma to React component names
components = components.map((component) => ({
...component,
name: component.name
.split(/[.-]/g)
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
.join(''),
}))

const uniqueNames = new Set([...components.map((c) => c.name)])

const file = 'src/components/icons.figma.tsx'
fs.mkdirSync(path.dirname(file), { recursive: true })
fs.writeFileSync(
file,
`\
import figma from '@figma/code-connect'
import {
${Array.from(uniqueNames)
.map((iconName) => ` ${iconName},`)
.join('\n')}
} from './Icons'
const props = {
size: figma.enum('Size', {
"12": 12,
"16": 16,
"24": 24,
})
}
${components
.map(
(c) => `figma.connect(${c.name}, '${c.figmaUrl}', {
props,
example: ({ size }) => <${c.name} size={size} />
})`,
)
.join('\n')}
`,
)
}

generateIconsWithSizeProp()
Loading

0 comments on commit 622b705

Please sign in to comment.