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

Mob 35767 fix color generation #59

Merged
merged 13 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from 10 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
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ final class DefaultBaseColorTokensGenerator: BaseColorTokensGenerator {

return BaseColorToken(
path: token.name.components(separatedBy: "."),
value: try tokensResolver.resolveHexColorValue(value, tokenValues: tokenValues)
value: try tokensResolver.resolveHexColorValue(value, tokenValues: tokenValues, theme: .undefined)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ final class DefaultFontFamilyTokensGenerator: FontFamilyTokensGenerator {

return FontFamilyToken(
path: tokenValue.name.components(separatedBy: "."),
value: try tokensResolver.resolveValue(value, tokenValues: tokenValues)
value: try tokensResolver.resolveValue(value, tokenValues: tokenValues, theme: .undefined)
)
}
}
Expand All @@ -37,7 +37,7 @@ final class DefaultFontFamilyTokensGenerator: FontFamilyTokensGenerator {

return FontWeightToken(
path: tokenValue.name.components(separatedBy: "."),
value: try tokensResolver.resolveValue(value, tokenValues: tokenValues)
value: try tokensResolver.resolveValue(value, tokenValues: tokenValues, theme: .undefined)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ final class DefaultSpacingTokensGenerator: SpacingTokensGenerator {

return SpacingToken(
path: token.name.components(separatedBy: "."),
value: try tokensResolver.resolveValue(value, tokenValues: tokenValues)
value: try tokensResolver.resolveValue(value, tokenValues: tokenValues, theme: .undefined)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ final class DefaultTypographyTokensGenerator: TypographyTokensGenerator {
tokenValues: TokenValues
) throws -> TypographyToken.LineHeightToken {
let lineHeightValue = value.lineHeight
let lineHeightResolvedValue = try tokensResolver.resolveValue(lineHeightValue, tokenValues: tokenValues)
let lineHeightResolvedValue = try tokensResolver.resolveValue(
lineHeightValue,
tokenValues: tokenValues,
theme: .undefined
)

guard lineHeightResolvedValue.hasSuffix("%") else {
return TypographyToken.LineHeightToken(
Expand All @@ -30,7 +34,9 @@ final class DefaultTypographyTokensGenerator: TypographyTokensGenerator {
)
}

let fontSize = Double(try tokensResolver.resolveValue(value.fontSize, tokenValues: tokenValues))
let fontSize = Double(
try tokensResolver.resolveValue(value.fontSize, tokenValues: tokenValues, theme: .undefined)
)
let lineHeight = Double(lineHeightResolvedValue.dropLast()).map { $0 / 100.0 }

guard let fontSize else {
Expand Down Expand Up @@ -59,12 +65,12 @@ final class DefaultTypographyTokensGenerator: TypographyTokensGenerator {

let letterSpacing = Double(
try tokensResolver
.resolveValue(letterSpacingValue, tokenValues: tokenValues)
.resolveValue(letterSpacingValue, tokenValues: tokenValues, theme: .undefined)
.removingFirst("%")
).map { $0 / 100.0 }

let fontSize = Double(
try tokensResolver.resolveValue(value.fontSize, tokenValues: tokenValues)
try tokensResolver.resolveValue(value.fontSize, tokenValues: tokenValues, theme: .undefined)
)

guard let fontSize else {
Expand All @@ -86,7 +92,7 @@ final class DefaultTypographyTokensGenerator: TypographyTokensGenerator {
private func makeContextToken(value: String, tokenValues: TokenValues) throws -> ContextToken {
ContextToken(
path: value.components(separatedBy: "."),
value: try tokensResolver.resolveValue(value, tokenValues: tokenValues)
value: try tokensResolver.resolveValue(value, tokenValues: tokenValues, theme: .undefined)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ final class DefaultColorTokensContextProvider: ColorTokensContextProvider {
return fallbackValue
}

return try tokensResolver.resolveHexColorValue(nightValue, tokenValues: tokenValues)
return try tokensResolver.resolveHexColorValue(nightValue, tokenValues: tokenValues, theme: .night)
}

private func resolveNightReference(
Expand All @@ -51,7 +51,34 @@ final class DefaultColorTokensContextProvider: ColorTokensContextProvider {
return fallbackRefence
}

return nightValue
return resolveReference(initialReferenceName: nightValue, themeColorTokenValues: tokenValues.night)
}

private func resolveReference(
initialReferenceName: String,
themeColorTokenValues: [TokenValue]
) -> String {
if initialReferenceName.contains("color.base") {
return initialReferenceName
}

guard let replaceValue = themeColorTokenValues.first(where: { initialReferenceName.contains($0.name) })?
.type.stringValue else {
return initialReferenceName
}

let nsString = initialReferenceName as NSString
guard
let tokenRegex = try? NSRegularExpression(pattern: #"\{.*?\}"#),
let firstArgument = tokenRegex.firstMatch(
in: initialReferenceName,
range: NSRange(location: 0, length: initialReferenceName.count)
)
else {
return initialReferenceName
}

return nsString.replacingCharacters(in: firstArgument.range, with: replaceValue) as String
}

private func makeColorToken(
Expand All @@ -62,13 +89,14 @@ final class DefaultColorTokensContextProvider: ColorTokensContextProvider {
) throws -> ColorToken {
let dayHexColorValue = try tokensResolver.resolveHexColorValue(
dayValue,
tokenValues: tokenValues
tokenValues: tokenValues,
theme: .day
)

return ColorToken(
dayTheme: ColorToken.Theme(
value: dayHexColorValue,
reference: dayValue
reference: resolveReference(initialReferenceName: dayValue, themeColorTokenValues: tokenValues.day)
),
nightTheme: ColorToken.Theme(
value: try resolveNightValue(
Expand Down Expand Up @@ -131,7 +159,7 @@ final class DefaultColorTokensContextProvider: ColorTokensContextProvider {

let path = token.name.components(separatedBy: ".")

guard path[0] != "gradient" else {
guard path[0] != "gradient" && !dayValue.contains("gradient") else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А зачем тут эта проверка? path[0] != "gradient" проверяет и так, что значение не начинается с gradient

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Там появились новые токены у которых gradient только в value, ранее проверялся только name

    {
      "name": "color.component.scrollable-container.fade.content",
      "value": "linear-gradient(0deg, rgba( {color.base.black} , {semantic.opacity.transparent}) 0%, {color.base.black} {semantic.opacity.visible})",
      "type": "color",
      "$extensions": {
        "id": "928293bc-254c-4bab-801d-7b98132d150b"
      }
    },
    ```

return nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ final class DefaultTokensResolver: TokensResolver {
return hexFloat / 255.0
}

private func makeColor(hex: String, alpha: CGFloat) throws -> Color {
private func makeColor(hex: String, alpha: CGFloat, tokenName: String) throws -> Color {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tokenName не используется?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Да, спасибо! Я хотела прокинуть в ошибку .invalidHEXComponent tokenName, но оказывается по code style нельзя только в 1 case enum-a прокинуть второй параметр. И я удалила этот код. Но часть забыла.

let hex = hex
.replacingOccurrences(of: "#", with: "")
.trimmingCharacters(in: .whitespacesAndNewlines)
Expand Down Expand Up @@ -60,18 +60,18 @@ final class DefaultTokensResolver: TokensResolver {
}
}

private func resolveColorValue(_ value: String, tokenValues: TokenValues) throws -> Color {
private func resolveColorValue(_ value: String, tokenValues: TokenValues, theme: Theme) throws -> Color {
if value.hasPrefix("rgba") {
return try resolveRGBAColorValue(value, tokenValues: tokenValues)
return try resolveRGBAColorValue(value, tokenValues: tokenValues, theme: theme)
}

return try makeColor(hex: value, alpha: 1.0)
return try makeColor(hex: value, alpha: 1.0, tokenName: value)
}

// MARK: - TokensResolver

func resolveValue(_ value: String, tokenValues: TokenValues) throws -> String {
let allTokens = tokenValues.all
func resolveValue(_ value: String, tokenValues: TokenValues, theme: Theme) throws -> String {
let themeTokens = tokenValues.getThemeTokenValues(theme: theme)

let resolvedValue = try value.replacingOccurrences(matchingPattern: #"\{.*?\}"#) { referenceName in
let referenceName = String(
Expand All @@ -80,22 +80,22 @@ final class DefaultTokensResolver: TokensResolver {
.dropLast()
)

guard let token = allTokens.first(where: { $0.name == referenceName }) else {
guard let token = themeTokens.first(where: { $0.name == referenceName }) else {
throw TokensGeneratorError(code: .referenceNotFound(name: referenceName))
}

guard let value = token.type.stringValue else {
throw TokensGeneratorError(code: .unexpectedTokenValueType(name: referenceName))
}

return try resolveValue(value, tokenValues: tokenValues)
return try resolveValue(value, tokenValues: tokenValues, theme: theme)
}

return evaluteValue(resolvedValue)
}

func resolveRGBAColorValue(_ value: String, tokenValues: TokenValues) throws -> Color {
let components = try resolveValue(value, tokenValues: tokenValues)
func resolveRGBAColorValue(_ value: String, tokenValues: TokenValues, theme: Theme) throws -> Color {
let components = try resolveValue(value, tokenValues: tokenValues, theme: theme)
.slice(from: "(", to: ")", includingBounds: false)?
.components(separatedBy: ", ")

Expand All @@ -110,21 +110,20 @@ final class DefaultTokensResolver: TokensResolver {
throw TokensGeneratorError(code: .invalidAlphaComponent(alpha: alphaPercent))
}

return try makeColor(hex: hex, alpha: alpha / 100.0)
return try makeColor(hex: hex, alpha: alpha / 100.0, tokenName: value)
}

func resolveHexColorValue(_ value: String, tokenValues: TokenValues) throws -> String {
let resolvedValue = try resolveValue(value, tokenValues: tokenValues)
func resolveHexColorValue(_ value: String, tokenValues: TokenValues, theme: Theme) throws -> String {
let resolvedValue = try resolveValue(value, tokenValues: tokenValues, theme: theme)

if resolvedValue.hasPrefix("#") {
return resolvedValue
}

return try resolveColorValue(resolvedValue, tokenValues: tokenValues).hexString
return try resolveColorValue(resolvedValue, tokenValues: tokenValues, theme: theme).hexString
}

func resolveLinearGradientValue(_ value: String, tokenValues: TokenValues) throws -> LinearGradient {
let value = try resolveValue(value, tokenValues: tokenValues)
func resolveLinearGradientValue(_ value: String, tokenValues: TokenValues, theme: Theme) throws -> LinearGradient {
let value = try resolveValue(value, tokenValues: tokenValues, theme: theme)

guard let startFunctionIndex = value.firstIndex(of: "("), let endFunctionIndex = value.lastIndex(of: ")") else {
throw TokensGeneratorError(code: .failedToExtractLinearGradientParams(linearGradient: value))
Expand All @@ -148,7 +147,7 @@ final class DefaultTokensResolver: TokensResolver {

let percentage = String(rawColorStop[separatorRange.upperBound...])
let rawColor = String(rawColorStop[...separatorRange.lowerBound])
let color = try resolveColorValue(rawColor, tokenValues: tokenValues)
let color = try resolveColorValue(rawColor, tokenValues: tokenValues, theme: theme)

return LinearGradient.LinearColorStop(color: color, percentage: percentage)
}
Expand Down
12 changes: 8 additions & 4 deletions Sources/FigmaGen/Generators/Tokens/Resolver/TokensResolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ protocol TokensResolver {
/// - Parameters:
/// - value: String value to resolve
/// - tokenValues: All token values
/// - theme: Theme
/// - Returns: Resolved value.
func resolveValue(_ value: String, tokenValues: TokenValues) throws -> String
func resolveValue(_ value: String, tokenValues: TokenValues, theme: Theme) throws -> String

/// Resolving references and mathematical expressions in `value` using ``resolveValue(_:tokenValues:)``
/// and convert `rgba()` to ``Color`` object
Expand All @@ -34,8 +35,9 @@ protocol TokensResolver {
/// )
/// ```
/// - tokenValues: All token values
/// - theme: Theme
/// - Returns: ``Color`` object with values resolved from `rgba()`
func resolveRGBAColorValue(_ value: String, tokenValues: TokenValues) throws -> Color
func resolveRGBAColorValue(_ value: String, tokenValues: TokenValues, theme: Theme) throws -> Color

/// Resolving references and mathematical expressions in `value` using ``resolveValue(_:tokenValues:)``
/// and convert `rgba()` to hex value
Expand All @@ -52,8 +54,9 @@ protocol TokensResolver {
/// ```
/// Or simple reference to another color: `{color.base.white}`
/// - tokenValues: All token values
/// - theme: Theme
/// - Returns: Hex value of the color
func resolveHexColorValue(_ value: String, tokenValues: TokenValues) throws -> String
func resolveHexColorValue(_ value: String, tokenValues: TokenValues, theme: Theme) throws -> String

/// Resolving references and mathematical expressions in `value` using ``resolveValue(_:tokenValues:)``
/// and convert `linear-gradient()` to ``LinearGradient`` object
Expand All @@ -73,6 +76,7 @@ protocol TokensResolver {
/// )
/// ```
/// - tokenValues: All token values
/// - theme: Theme
/// - Returns: ``LinearGradient`` object with values resolved from `linear-gradient()`
func resolveLinearGradientValue(_ value: String, tokenValues: TokenValues) throws -> LinearGradient
func resolveLinearGradientValue(_ value: String, tokenValues: TokenValues, theme: Theme) throws -> LinearGradient
}
7 changes: 7 additions & 0 deletions Sources/FigmaGen/Models/Token/Theme.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Foundation

enum Theme: Codable {
case day
case night
case undefined
}
15 changes: 13 additions & 2 deletions Sources/FigmaGen/Models/Token/TokenValues.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,18 @@ struct TokenValues: Codable, Hashable {

// MARK: - Instance Properties

var all: [TokenValue] {
[core, semantic, colors, typography, day, night].flatMap { $0 }
// Возвращает набор токенов для определенной темы.
// Для undefined возвращается полный набор токенов. Нужен для Spacer, Font и других независимых от темы параметров.
func getThemeTokenValues(theme: Theme) -> [TokenValue] {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нужно три слэша, тогда это будет документация метода:

/// Возвращает набор токенов для определенной темы.
/// Для undefined возвращается полный набор токенов. Нужен для Spacer, Font и других независимых от темы параметров.
func getThemeTokenValues(theme: Theme) -> [TokenValue] {

switch theme {
case .day:
return [day, core, semantic, colors, typography].flatMap { $0 }

case .night:
return [night, core, semantic, colors, typography].flatMap { $0 }

case .undefined:
return [core, semantic, colors, typography, day, night].flatMap { $0 }
}
}
}
Loading
Loading