Skip to content

Commit

Permalink
Support high contrast colors (#157)
Browse files Browse the repository at this point in the history
* Update the Params file

add lightHighContrastFileId and darkHighContrastFileId
add lightHCModeSuffix and darkHCModeSuffix

* Update the models files

* Update the Loader file

* Update the Processor files

and the AssetPair

* Update CONFIG

* Revert indentations changes

* Fix filter for loader

* Add filteredColors

* Fix dark palette comment

dark palette → dark high contrast palette ?

* Fix AssetsValidatorError comment

* Fix AssetsProcessor

* Fix logic

* Add Zip4Sequence

From https://github.com/amomchilov/ZipNsequence/blob/master/Zip4Sequence.swift

* Update AssetsProcessor

* Add AssetsProcessorTests

* Update READMY

* Fix typo hight → high

* Fix error description to AssetsValidatorError

* Fix AssetPair

* Fix AssetsProcessor

* Fix example project

* Fix XcodeColorExporte

* Fix XcodeExportExtensions.swift

* Fix 2 XcodeExportExtensions.swift

* Update AssetsValidatorError.darkAssetsNotFoundInLightPalette
  • Loading branch information
alexey1312 authored Apr 2, 2022
1 parent cf6998a commit 1438b90
Show file tree
Hide file tree
Showing 15 changed files with 666 additions and 184 deletions.
8 changes: 8 additions & 0 deletions CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ figma:
lightFileId: shPilWnVdJfo10YF12345
# [optional] Identifier of the file containing dark color palette and dark images.
darkFileId: KfF6DnJTWHGZzC912345
# [optional] Identifier of the file containing light high contrast color palette.
lightHighContrastFileId: KfF6DnJTWHGZzC912345
# [optional] Identifier of the file containing dark high contrast color palette.
darkHighContrastFileId: KfF6DnJTWHGZzC912345
# [optional] Figma API request timeout. The default value of this property is 30 (seconds). If you have a lot of resources to export set this value to 60 or more to give Figma API more time to prepare resources for exporting.
# timeout: 30

Expand All @@ -30,6 +34,10 @@ common:
useSingleFile: true
# [optional] If useSingleFile is true, customize the suffix to denote a dark mode color. Defaults to '_dark'
darkModeSuffix: '_dark'
# [optional] If useSingleFile is true, customize the suffix to denote a light high contrast color. Defaults to '_lightHC'
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 Down
4 changes: 2 additions & 2 deletions Examples/Example/figma-export.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ common:
# [optional]
colors:
# [optional] RegExp pattern for color name validation before exporting. Use to validate color name in Figma file
nameValidateRegexp: '^[a-zA-Z_]+$' # RegExp pattern for: background, background_primary, widget_primary_background
nameValidateRegexp: '^([a-zA-Z_]+)$' # RegExp pattern for: background, background_primary, widget_primary_background
# [optional]
icons:
# [optional] RegExp pattern for icon name validation before exporting. Use to validate icon name in Figma file
Expand All @@ -32,7 +32,7 @@ ios:
# Parameters for exporting colors
colors:
# Should be generate color assets instead of pure swift code
useColorAssets: True
useColorAssets: true
# Name of the folder inside Assets.xcassets where to place colors (.colorset directories)
assetsFolder: Colors
# Color name style: camelCase or snake_case
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Table of Contents:
* Export images to Xcode / Android Studio project
* Export text styles to Xcode / Android Studio project
* Supports Dark Mode
* Supports High contrast colors for Xcode
* Supports SwiftUI and UIKit
* Supports Objective-C

Expand Down Expand Up @@ -454,7 +455,11 @@ For `figma-export colors`

By default, if you support dark mode your Figma project must contains two files. One should contains a dark color palette, and the another light color palette. If you would like to specify light and dark colors in the same file, you can do so with the `useSingleFile` configuration option. You can then denote dark mode colors by adding a suffix like `_dark`. The suffix is also configurable. See [CONFIG.md](CONFIG.md) for more information in the colors section.

The light color palette may contain more colors than the dark color palette. If a light-only color is present, it will be considered as universal color for the iOS color palette. Names of the dark colors must match the light colors.
If you support high contrast mode without dark mode your Figma project must contains two files. One should contains a high contrast color palette, and the another light color palette. If you would like to specify light and high contrast colors in the same file, you can do so with the `useSingleFile` configuration option. You can then denote high contrast mode colors by adding a suffix like `_lightHC`. The suffix is also configurable. See [CONFIG.md](CONFIG.md) for more information in the colors section.

If you support high contrast mode with dark mode your Figma project must contains four files. Should be like this: light, dark, high contrast light, high contrast dark. If you would like to specify colors in the same file, you can do so with the `useSingleFile` configuration option. You can then denote high contrast mode colors by adding a suffix like `_lightHC` for light and `_darkHC` for dark high contrast colors. The suffix is also configurable. See [CONFIG.md](CONFIG.md) for more information in the colors section.

The light color palette may contain more colors than the dark or high light color palette wherein the dark color palette may contain more colors than the high dark color palette. If a light-only color is present, it will be considered as universal color for the iOS color palette. Names of the dark, high light and high dark colors must match the light colors.

Example

Expand Down
4 changes: 4 additions & 0 deletions Sources/FigmaExport/Input/Params.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ struct Params: Decodable {
struct Figma: Decodable {
let lightFileId: String
let darkFileId: String?
let lightHighContrastFileId: String?
let darkHighContrastFileId: String?
let timeout: TimeInterval?
}

Expand All @@ -17,6 +19,8 @@ struct Params: Decodable {
let nameReplaceRegexp: String?
let useSingleFile: Bool?
let darkModeSuffix: String?
let lightHCModeSuffix: String?
let darkHCModeSuffix: String?
}

struct Icons: Decodable {
Expand Down
47 changes: 34 additions & 13 deletions Sources/FigmaExport/Loaders/ColorsLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,55 @@ final class ColorsLoader {
self.figmaParams = figmaParams
self.colorParams = colorParams
}

func load() throws -> (light: [Color], dark: [Color]?) {
if let useSingleFile = colorParams?.useSingleFile, useSingleFile {
return try loadColorsFromSingleFile()
} else {

func load() throws -> (light: [Color], dark: [Color]?, lightHC: [Color]?, darkHC: [Color]?) {
guard let useSingleFile = colorParams?.useSingleFile, useSingleFile else {
return try loadColorsFromLightAndDarkFile()
}
return try loadColorsFromSingleFile()
}

private func loadColorsFromLightAndDarkFile() throws -> (light: [Color], dark: [Color]?) {
private func loadColorsFromLightAndDarkFile() throws -> (light: [Color],
dark: [Color]?,
lightHC: [Color]?,
darkHC: [Color]?) {
let lightColors = try loadColors(fileId: figmaParams.lightFileId)
let darkColors = try figmaParams.darkFileId.map { try loadColors(fileId: $0) }
return (lightColors, darkColors)
let lightHighContrastColors = try figmaParams.lightHighContrastFileId.map { try loadColors(fileId: $0) }
let darkHighContrastColors = try figmaParams.darkHighContrastFileId.map { try loadColors(fileId: $0) }
return (lightColors, darkColors, lightHighContrastColors, darkHighContrastColors)
}

private func loadColorsFromSingleFile() throws -> (light: [Color], dark: [Color]?) {
private func loadColorsFromSingleFile() throws -> (light: [Color],
dark: [Color]?,
lightHC: [Color]?,
darkHC: [Color]?) {
let colors = try loadColors(fileId: figmaParams.lightFileId)
let darkSuffix = colorParams?.darkModeSuffix ?? "_dark"
let lightHCSuffix = colorParams?.lightHCModeSuffix ?? "_lightHC"
let darkHCSuffix = colorParams?.darkHCModeSuffix ?? "_darkHC"

let lightColors = colors
.filter { !$0.name.hasSuffix(darkSuffix) }
let darkColors = colors
.filter { $0.name.hasSuffix(darkSuffix) }
.filter {
!$0.name.hasSuffix(darkSuffix) &&
!$0.name.hasSuffix(lightHCSuffix) &&
!$0.name.hasSuffix(darkHCSuffix)
}
let darkColors = filteredColors(colors, suffix: darkSuffix)
let lightHCColors = filteredColors(colors, suffix: lightHCSuffix)
let darkHCColors = filteredColors(colors, suffix: darkHCSuffix)
return (lightColors, darkColors, lightHCColors, darkHCColors)
}

private func filteredColors(_ colors: [Color], suffix: String) -> [Color] {
let filteredColors = colors
.filter { $0.name.hasSuffix(suffix) }
.map { color -> Color in
var newColor = color
newColor.name = String(color.name.dropLast(darkSuffix.count))
newColor.name = String(color.name.dropLast(suffix.count))
return newColor
}
return (lightColors, darkColors)
return filteredColors
}

private func loadColors(fileId: String) throws -> [Color] {
Expand Down
9 changes: 6 additions & 3 deletions Sources/FigmaExport/Subcommands/ExportColors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ extension FigmaExportCommand {
nameReplaceRegexp: options.params.common?.colors?.nameReplaceRegexp,
nameStyle: options.params.ios?.colors?.nameStyle
)
let colorPairs = processor.process(light: colors.light, dark: colors.dark)
let colorPairs = processor.process(light: colors.light,
dark: colors.dark,
lightHC: colors.lightHC,
darkHC: colors.darkHC)
if let warning = colorPairs.warning?.errorDescription {
logger.warning("\(warning)")
}
Expand Down Expand Up @@ -68,7 +71,7 @@ extension FigmaExportCommand {
logger.info("Done!")
}
}

private func exportXcodeColors(colorPairs: [AssetPair<Color>], iosParams: Params.iOS) throws {
guard let colorParams = iosParams.colors else {
logger.error("Nothing to do. Add ios.colors parameters to the config file.")
Expand Down Expand Up @@ -97,7 +100,7 @@ extension FigmaExportCommand {

let exporter = XcodeColorExporter(output: output)
let files = try exporter.export(colorPairs: colorPairs)

if colorParams.useColorAssets, let url = colorsURL {
try? FileManager.default.removeItem(atPath: url.path)
}
Expand Down
11 changes: 10 additions & 1 deletion Sources/FigmaExportCore/AssetPair.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@ public struct AssetPair<AssetType> where AssetType: Asset {

public let light: AssetType
public let dark: AssetType?
public let lightHC: AssetType?
public let darkHC: AssetType?

public init(light: AssetType, dark: AssetType?) {
public init(
light: AssetType,
dark: AssetType?,
lightHC: AssetType? = nil,
darkHC: AssetType? = nil
) {
self.light = light
self.dark = dark
self.lightHC = lightHC
self.darkHC = darkHC
}
}
Loading

0 comments on commit 1438b90

Please sign in to comment.