Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spacing Grid export support #176

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ common:
lightHCModeSuffix: '_lightHC'
# [optional] If useSingleFile is true, customize the suffix to denote a dark high contrast color. Defaults to '_darkHC'
darkHCModeSuffix: '_darkHC'

# [optional]
icons:
# [optional] Name of the Figma's frame where icons components are located
Expand All @@ -50,6 +51,7 @@ common:
useSingleFile: true
# [optional] If useSingleFile is true, customize the suffix to denote a dark mode icons. Defaults to '_dark'
darkModeSuffix: '_dark'

# [optional]
images:
# [optional]Name of the Figma's frame where image components are located
Expand All @@ -62,12 +64,26 @@ common:
useSingleFile: true
# [optional] If useSingleFile is true, customize the suffix to denote a dark mode icons. Defaults to '_dark'
darkModeSuffix: '_dark'

# [optional]
typography:
# [optional] RegExp pattern for text style name validation before exporting. If a name contains "/" symbol it will be replaced by "_" before executing the RegExp
nameValidateRegexp: '^[a-zA-Z0-9_]+$' # RegExp pattern for: h1_regular, h1_medium
# [optional] RegExp pattern for replacing. Supports only $n
nameReplaceRegexp: 'font_$1'

# [optional]
spacings:
# [optional] Frame name containing spacings
figmaFrameName: 'Spacings'
# [optional] Containing state name for vertical spacings
figmaVerticalStateName: 'Vertical'
# [optional] Containing state name for horizontal spacings
figmaHorizontalStateName: 'Horizontal'
# [optional] RegExp pattern for text style name validation before exporting. If a name contains "/" symbol it will be replaced by "_" before executing the RegExp
nameValidateRegexp: '^[a-zA-Z0-9_]+$' # RegExp pattern for: h1_regular, h1_medium
# [optional] RegExp pattern for replacing. Supports only $n
nameReplaceRegexp: 'font_$1'

# [optional] iOS export parameters
ios:
Expand Down Expand Up @@ -157,6 +173,13 @@ ios:
labelsDirectory: "./Source/UIComponents/"
# Typography name style: camelCase or snake_case
nameStyle: camelCase

# [optional] Parameters for exporting spacings
spacings:
# Relative or absolute path to directory where to place generated Spacings.swift file
spacingsSwift: "./Source/UIComponents/"
# Spacing name style: camelCase or snake_case
nameStyle: camelCase

# [optional] Android export parameters
android:
Expand All @@ -173,12 +196,14 @@ android:
colors:
# [optional] The package to export the Jetpack Compose color code to. Note: To export Jetpack Compose code, also `mainSrc` and `resourcePackage` above must be set
composePackageName: "com.example"

# Parameters for exporting icons
icons:
# Where to place icons relative to `mainRes`? FigmaExport clears this directory every time your execute `figma-export icons` command
output: "figma-import-icons"
# [optional] The package to export the Jetpack Compose icon code to. Note: To export Jetpack Compose code, also `mainSrc` and `resourcePackage` above must be set
composePackageName: "com.example"

# Parameters for exporting images
images:
# Image file format: svg or png
Expand All @@ -193,10 +218,18 @@ android:
encoding: lossy
# Encoding quality in percents. Only for lossy encoding.
quality: 90

# Parameters for exporting typography
typography:
# Typography name style: camelCase or snake_case
nameStyle: camelCase
# [optional] The package to export the Jetpack Compose typography code to. Note: To export Jetpack Compose code, also `mainSrc` and `resourcePackage` above must be set
composePackageName: "com.example"

# Parameters for exporting spacings
spacings:
# Spacings name style: camelCase or snake_case
nameStyle: camelCase
# [optional] The package to export the Jetpack Compose typography code to. Note: To export Jetpack Compose code, also `mainSrc` and `resourcePackage` above must be set
composePackageName: "com.example"
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.redmadrobot.androidcomposeexample.ui.figmaexport

import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import com.redmadrobot.androidcomposeexample.R

object Spacings

@Composable
@ReadOnlyComposable
fun Spacings.h12(): Dp = dimensionResource(id = R.dimen.h12)

@Composable
@ReadOnlyComposable
fun Spacings.h16(): Dp = dimensionResource(id = R.dimen.h16)

@Composable
@ReadOnlyComposable
fun Spacings.h24(): Dp = dimensionResource(id = R.dimen.h24)

@Composable
@ReadOnlyComposable
fun Spacings.h32(): Dp = dimensionResource(id = R.dimen.h32)

@Composable
@ReadOnlyComposable
fun Spacings.h4(): Dp = dimensionResource(id = R.dimen.h4)

@Composable
@ReadOnlyComposable
fun Spacings.h48(): Dp = dimensionResource(id = R.dimen.h48)

@Composable
@ReadOnlyComposable
fun Spacings.h64(): Dp = dimensionResource(id = R.dimen.h64)

@Composable
@ReadOnlyComposable
fun Spacings.h8(): Dp = dimensionResource(id = R.dimen.h8)

@Composable
@ReadOnlyComposable
fun Spacings.v12(): Dp = dimensionResource(id = R.dimen.v12)

@Composable
@ReadOnlyComposable
fun Spacings.v16(): Dp = dimensionResource(id = R.dimen.v16)

@Composable
@ReadOnlyComposable
fun Spacings.v24(): Dp = dimensionResource(id = R.dimen.v24)

@Composable
@ReadOnlyComposable
fun Spacings.v32(): Dp = dimensionResource(id = R.dimen.v32)

@Composable
@ReadOnlyComposable
fun Spacings.v4(): Dp = dimensionResource(id = R.dimen.v4)

@Composable
@ReadOnlyComposable
fun Spacings.v48(): Dp = dimensionResource(id = R.dimen.v48)

@Composable
@ReadOnlyComposable
fun Spacings.v64(): Dp = dimensionResource(id = R.dimen.v64)

@Composable
@ReadOnlyComposable
fun Spacings.v8(): Dp = dimensionResource(id = R.dimen.v8)
20 changes: 17 additions & 3 deletions Examples/AndroidComposeExample/app/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="h12">12.0dp</dimen>
<dimen name="h16">16.0dp</dimen>
<dimen name="h24">24.0dp</dimen>
<dimen name="h32">32.0dp</dimen>
<dimen name="h4">4.0dp</dimen>
<dimen name="h48">48.0dp</dimen>
<dimen name="h64">64.0dp</dimen>
<dimen name="h8">8.0dp</dimen>
<dimen name="v12">12.0dp</dimen>
<dimen name="v16">16.0dp</dimen>
<dimen name="v24">24.0dp</dimen>
<dimen name="v32">32.0dp</dimen>
<dimen name="v4">4.0dp</dimen>
<dimen name="v48">48.0dp</dimen>
<dimen name="v64">64.0dp</dimen>
<dimen name="v8">8.0dp</dimen>
</resources>
30 changes: 30 additions & 0 deletions Examples/Example/UIComponents/Source/Spacings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// swiftlint:disable all
//
// The code generated using FigmaExport — Command line utility to export
// colors, typography, icons and images from Figma to Xcode project.
//
// https://github.com/RedMadRobot/figma-export
//
// Don’t edit this code manually to avoid runtime crashes
//

import Foundation

public struct Spacings {
static let h12: Double = 12.0
static let h16: Double = 16.0
static let h24: Double = 24.0
static let h32: Double = 32.0
static let h4: Double = 4.0
static let h48: Double = 48.0
static let h64: Double = 64.0
static let h8: Double = 8.0
static let v12: Double = 12.0
static let v16: Double = 16.0
static let v24: Double = 24.0
static let v32: Double = 32.0
static let v4: Double = 4.0
static let v48: Double = 48.0
static let v64: Double = 64.0
static let v8: Double = 8.0
}
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Command line utility to export colors, typography, icons and images from Figma t
* typography - Figma's text style
* icon — Figma's component with small black/colorized vector image
* image — Figma's components with colorized image (Light/Dark)
* spacings — Figma's components defining spacing between other components

The utility supports Dark Mode, SwiftUI and Jetpack Compose.

Expand Down Expand Up @@ -199,6 +200,31 @@ Example of these files:
- [./Examples/Example/UIComponents/Source/LabelStyle.swift](./Examples/Example/UIComponents/Source/LabelStyle.swift)
- [./Examples/Example/UIComponents/Source/UIFont+extension.swift](./Examples/Example/UIComponents/Source/UIFont+extension.swift)

#### Spacings
When your execute `figma-export spacings` command `figma-export` generates a Spacings.swift that looks like this:
```swift
import Foundation

public struct Spacings {
static let h12: Double = 12.0
static let h16: Double = 16.0
static let h24: Double = 24.0
static let h32: Double = 32.0
static let h4: Double = 4.0
static let h48: Double = 48.0
static let h64: Double = 64.0
static let h8: Double = 8.0
static let v12: Double = 12.0
static let v16: Double = 16.0
static let v24: Double = 24.0
static let v32: Double = 32.0
static let v4: Double = 4.0
static let v48: Double = 48.0
static let v64: Double = 64.0
static let v8: Double = 8.0
}
```

### Android

Colors will be exported to `values/colors.xml` and `values-night/colors.xml` files.
Expand Down Expand Up @@ -258,6 +284,27 @@ object Typography {
}
```

Spacings will be exported to `values/dimens.xml`. For Jetpack Compose, following code will be generated, if configured:
```kotlin
package com.redmadrobot.androidcomposeexample.ui.figmaexport

import ...

object Spacings

@Composable
@ReadOnlyComposable
fun Spacings.h12(): Dp = dimensionResource(id = R.dimen.h12)

@Composable
@ReadOnlyComposable
fun Spacings.h16(): Dp = dimensionResource(id = R.dimen.h16)

@Composable
@ReadOnlyComposable
fun Spacings.h24(): Dp = dimensionResource(id = R.dimen.h24)
```

## Installation

Before installation you must provide Figma personal access token via environment variables.
Expand Down
78 changes: 78 additions & 0 deletions Sources/AndroidExport/AndroidSpacingsExporter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import Foundation
import FigmaExportCore

final public class AndroidSpacingsExporter: AndroidExporter {

private let output: AndroidOutput

public init(output: AndroidOutput) {
self.output = output
super.init(templatesPath: output.templatesPath)
}

public func exportSpacings(spacings: [Spacing]) throws -> [FileContents] {
var files: [FileContents] = []

// typography.xml
files.append(try makeSpacingsXMLFileContents(spacings: spacings))

// Typography.kt
if
let composeOutputDirectory = output.composeOutputDirectory,
let packageName = output.packageName,
let xmlResourcePackage = output.xmlResourcePackage {

files.append(
try makeSpacingsComposeFileContents(
spacings: spacings,
outputDirectory: composeOutputDirectory,
package: packageName,
xmlResourcePackage: xmlResourcePackage
)
)
}

return files
}

private func makeSpacingsXMLFileContents(spacings: [Spacing]) throws -> FileContents {
let env = makeEnvironment()
let contents = try env.renderTemplate(name: "spacings.xml.stencil", context: [
"spacings": spacings.map { spacing in
[
"name": spacing.name,
"size": spacing.size
]
}
])

let directoryURL = output.xmlOutputDirectory.appendingPathComponent("values")
let fileURL = URL(string: "dimens.xml")!
return try makeFileContents(for: contents, directory: directoryURL, file: fileURL)
}

private func makeSpacingsComposeFileContents(
spacings: [Spacing],
outputDirectory: URL,
package: String,
xmlResourcePackage: String
) throws -> FileContents {
let spacings: [[String: Any]] = spacings.map { spacing in
[
"functionName": spacing.name.lowerCamelCased(),
"name": spacing.name
]
}
let context: [String: Any] = [
"spacings": spacings,
"package": package,
"xmlResourcePackage": xmlResourcePackage
]
let env = makeEnvironment()
let contents = try env.renderTemplate(name: "Spacings.kt.stencil", context: context)

let fileURL = URL(string: "Spacings.kt")!
return try makeFileContents(for: contents, directory: outputDirectory, file: fileURL)
}
}

14 changes: 14 additions & 0 deletions Sources/AndroidExport/Resources/Spacings.kt.stencil
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package {{package}}

import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import {{xmlResourcePackage}}.R

object Spacings
{% for spacing in spacings %}
@Composable
@ReadOnlyComposable
fun Spacings.{{ spacing.functionName }}(): Dp = dimensionResource(id = R.dimen.{{ spacing.name }})
{% endfor %}
4 changes: 4 additions & 0 deletions Sources/AndroidExport/Resources/spacings.xml.stencil
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>{% for spacing in spacings %}
<dimen name="{{ spacing.name }}">{{ spacing.size }}dp</dimen>{% endfor %}
</resources>
Loading