Updated on 2026-08-14
This commit is contained in:
parent
3398db66e2
commit
56a2eda3e1
18 changed files with 2080 additions and 631 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit f4d2156236d7f77b61f26250351f6bfa72262a69
|
||||
Subproject commit 27202508b606f54c276afa577a2f3e7a3da27e8b
|
||||
|
|
@ -29,6 +29,10 @@ import com.tangem.core.ui.haptic.DefaultHapticManager
|
|||
import com.tangem.core.ui.haptic.HapticManager
|
||||
import com.tangem.core.ui.haptic.VibratorHapticManager
|
||||
import com.tangem.core.ui.message.EventMessageHandler
|
||||
import com.tangem.core.ui.res.generated.TangemColors3
|
||||
import com.tangem.core.ui.res.generated.TangemDimens3
|
||||
import com.tangem.core.ui.res.generated.TangemTypography3
|
||||
import com.tangem.core.ui.res.generated.lightColors3
|
||||
import com.tangem.core.ui.windowsize.WindowSize
|
||||
import com.tangem.core.ui.windowsize.rememberWindowSize
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
|
|
@ -161,11 +165,17 @@ object TangemTheme {
|
|||
@ReadOnlyComposable
|
||||
get() = LocalTangemColors.current
|
||||
|
||||
@Deprecated("Use colors3 instead", ReplaceWith("TangemTheme.colors3"))
|
||||
val colors2: TangemColors2
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = LocalTangemColors2.current
|
||||
|
||||
val colors3: TangemColors3
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = LocalTangemColors3.current
|
||||
|
||||
val typography: TangemTypography
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
|
|
@ -176,6 +186,11 @@ object TangemTheme {
|
|||
@ReadOnlyComposable
|
||||
get() = TangemTypography2(InterFamily)
|
||||
|
||||
val typography3: TangemTypography3
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = LocalTangemTypography3.current
|
||||
|
||||
val dimens: TangemDimens
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
|
|
@ -186,6 +201,11 @@ object TangemTheme {
|
|||
@ReadOnlyComposable
|
||||
get() = LocalTangemDimens2.current
|
||||
|
||||
val dimens3: TangemDimens3
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = LocalTangemDimens3.current
|
||||
|
||||
val shapes: TangemShapes
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
|
|
@ -366,6 +386,10 @@ internal val LocalTangemColors2 = staticCompositionLocalOf<TangemColors2> {
|
|||
error("No TangemColors2 provided")
|
||||
}
|
||||
|
||||
internal val LocalTangemColors3 = staticCompositionLocalOf {
|
||||
lightColors3()
|
||||
}
|
||||
|
||||
internal val LocalTangemTypography = staticCompositionLocalOf {
|
||||
TangemTypography(RobotoFamily)
|
||||
}
|
||||
|
|
@ -382,6 +406,14 @@ private val LocalTangemDimens2 = staticCompositionLocalOf {
|
|||
TangemDimens2()
|
||||
}
|
||||
|
||||
internal val LocalTangemDimens3 = staticCompositionLocalOf {
|
||||
TangemDimens3()
|
||||
}
|
||||
|
||||
internal val LocalTangemTypography3 = staticCompositionLocalOf {
|
||||
TangemTypography3(InterFamily)
|
||||
}
|
||||
|
||||
private val LocalTangemShapes = staticCompositionLocalOf<TangemShapes> {
|
||||
error("No TangemShapes provided")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@ import androidx.compose.runtime.*
|
|||
import androidx.compose.ui.Modifier
|
||||
import com.tangem.core.ui.components.haze.ProvideHaze
|
||||
import com.tangem.core.ui.components.haze.hazeSourceTangem
|
||||
import com.tangem.core.ui.res.generated.TangemDimens3
|
||||
import com.tangem.core.ui.res.generated.TangemTypography3
|
||||
import com.tangem.core.ui.res.generated.darkColors3
|
||||
import com.tangem.core.ui.res.generated.lightColors3
|
||||
|
||||
/**
|
||||
* Provides additional theming for redesigned components.
|
||||
|
|
@ -21,17 +25,30 @@ fun TangemThemeRedesign(content: @Composable () -> Unit) {
|
|||
val themeColors = if (LocalIsInDarkTheme.current) darkThemeColors() else lightThemeColors(redesign = true)
|
||||
val rememberedColors = remember { themeColors }
|
||||
.apply { update(themeColors) }
|
||||
|
||||
val themeColors3 = if (LocalIsInDarkTheme.current) darkColors3() else lightColors3()
|
||||
val rememberedColors3 = remember { themeColors3 }
|
||||
.apply { update(themeColors3) }
|
||||
|
||||
val rootBackgroundColor = rememberedColors.background.secondary
|
||||
|
||||
val tangemDimens3 = remember { TangemDimens3() }
|
||||
val tangemTypography3 = remember { TangemTypography3(InterFamily) }
|
||||
val tangemTypography2 = remember { TangemTypography2(InterFamily) }
|
||||
val tangemTypography = remember { TangemTypography(InterFamily) }
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = tangemColorScheme(colors = themeColors),
|
||||
colorScheme = tangemColorScheme(colors = rememberedColors),
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalRedesignEnabled provides true,
|
||||
LocalTangemColors provides themeColors,
|
||||
LocalTangemColors provides rememberedColors,
|
||||
LocalTangemColors2 provides if (LocalIsInDarkTheme.current) darkThemeColors2() else lightThemeColors2(),
|
||||
LocalTangemTypography2 provides TangemTypography2(InterFamily),
|
||||
LocalTangemTypography provides TangemTypography(InterFamily),
|
||||
LocalTangemColors3 provides rememberedColors3,
|
||||
LocalTangemDimens3 provides tangemDimens3,
|
||||
LocalTangemTypography3 provides tangemTypography3,
|
||||
LocalTangemTypography2 provides tangemTypography2,
|
||||
LocalTangemTypography provides tangemTypography,
|
||||
LocalRootBackgroundColor provides remember(rootBackgroundColor) { mutableStateOf(rootBackgroundColor) },
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
ddef7c44794c12a02c136fcc17f01fe51b6372d33a6a7eda4913d2d1b1f86203
|
||||
84387e888f54e5056380c38e077962bdfa4a32cfca194d822c13aa7e35661968
|
||||
|
|
|
|||
|
|
@ -0,0 +1,149 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
internal object TangemColorPalette {
|
||||
object Base {
|
||||
val black = Color(0xFF000000)
|
||||
val white = Color(0xFFFFFFFF)
|
||||
}
|
||||
|
||||
object Neutral {
|
||||
val `5` = Color(0xFFF4F4F4)
|
||||
val `10` = Color(0xFFEAEAEA)
|
||||
val `20` = Color(0xFFD0D0D0)
|
||||
val `30` = Color(0xFFB5B5B5)
|
||||
val `40` = Color(0xFF989898)
|
||||
val `50` = Color(0xFF838383)
|
||||
val `60` = Color(0xFF6F6F6F)
|
||||
val `70` = Color(0xFF4A4A4A)
|
||||
val `80` = Color(0xFF2C2C2C)
|
||||
val `90` = Color(0xFF1B1B1B)
|
||||
val `95` = Color(0xFF0F0F0F)
|
||||
}
|
||||
|
||||
object Blue {
|
||||
val `5` = Color(0xFFE9F7FF)
|
||||
val `10` = Color(0xFFDBF1FF)
|
||||
val `20` = Color(0xFF98D7FF)
|
||||
val `30` = Color(0xFF5EBDF9)
|
||||
val `40` = Color(0xFF109FF0)
|
||||
val `50` = Color(0xFF0090F9)
|
||||
val `60` = Color(0xFF0077E1)
|
||||
val `70` = Color(0xFF0C58AF)
|
||||
val `80` = Color(0xFF143C70)
|
||||
val `90` = Color(0xFF1B304A)
|
||||
val `95` = Color(0xFF101C2C)
|
||||
}
|
||||
|
||||
object Violet {
|
||||
val `5` = Color(0xFFF6F1FF)
|
||||
val `10` = Color(0xFFEEE7FD)
|
||||
val `20` = Color(0xFFDAC8FB)
|
||||
val `30` = Color(0xFFC5A5FC)
|
||||
val `40` = Color(0xFFB07BFD)
|
||||
val `50` = Color(0xFFA967FD)
|
||||
val `60` = Color(0xFF9258DC)
|
||||
val `70` = Color(0xFF67419B)
|
||||
val `80` = Color(0xFF473068)
|
||||
val `90` = Color(0xFF332846)
|
||||
val `95` = Color(0xFF201B2A)
|
||||
}
|
||||
|
||||
object Red {
|
||||
val `5` = Color(0xFFFFF0F7)
|
||||
val `10` = Color(0xFFFFE8EC)
|
||||
val `20` = Color(0xFFFFC0C3)
|
||||
val `30` = Color(0xFFFF979D)
|
||||
val `40` = Color(0xFFFF5E66)
|
||||
val `50` = Color(0xFFFE4142)
|
||||
val `60` = Color(0xFFE12C2E)
|
||||
val `70` = Color(0xFF9E2729)
|
||||
val `80` = Color(0xFF6D2323)
|
||||
val `90` = Color(0xFF4C2121)
|
||||
val `95` = Color(0xFF2B1818)
|
||||
}
|
||||
|
||||
object Orange {
|
||||
val `5` = Color(0xFFFFF0EA)
|
||||
val `10` = Color(0xFFFFE5DB)
|
||||
val `20` = Color(0xFFFFC3AD)
|
||||
val `30` = Color(0xFFFF9976)
|
||||
val `40` = Color(0xFFFA6931)
|
||||
val `50` = Color(0xFFF25508)
|
||||
val `60` = Color(0xFFD3480E)
|
||||
val `70` = Color(0xFF953715)
|
||||
val `80` = Color(0xFF652A18)
|
||||
val `90` = Color(0xFF43251A)
|
||||
val `95` = Color(0xFF2A1A13)
|
||||
}
|
||||
|
||||
object Green {
|
||||
val `5` = Color(0xFFEBF6ED)
|
||||
val `10` = Color(0xFFDCFBE3)
|
||||
val `20` = Color(0xFF9EE1AB)
|
||||
val `30` = Color(0xFF64C973)
|
||||
val `40` = Color(0xFF2DAE3B)
|
||||
val `50` = Color(0xFF2DA30D)
|
||||
val `60` = Color(0xFF208900)
|
||||
val `70` = Color(0xFF1E6110)
|
||||
val `80` = Color(0xFF1C4415)
|
||||
val `90` = Color(0xFF1D3319)
|
||||
val `95` = Color(0xFF162114)
|
||||
}
|
||||
|
||||
object Yellow {
|
||||
val `5` = Color(0xFFFAF3E5)
|
||||
val `10` = Color(0xFFFEF5E5)
|
||||
val `20` = Color(0xFFF7CA75)
|
||||
val `30` = Color(0xFFF4B42F)
|
||||
val `40` = Color(0xFFEFA210)
|
||||
val `50` = Color(0xFFE68A03)
|
||||
val `60` = Color(0xFFCD7A11)
|
||||
val `70` = Color(0xFF965001)
|
||||
val `80` = Color(0xFF573414)
|
||||
val `90` = Color(0xFF3D2918)
|
||||
val `95` = Color(0xFF241B13)
|
||||
}
|
||||
|
||||
object Opaque {
|
||||
object BaseBlack {
|
||||
val `5` = Color(0x0D000000)
|
||||
val `10` = Color(0x1A000000)
|
||||
val `15` = Color(0x26000000)
|
||||
val `20` = Color(0x33000000)
|
||||
val `25` = Color(0x40000000)
|
||||
val `30` = Color(0x4D000000)
|
||||
val `40` = Color(0x66000000)
|
||||
val `50` = Color(0x80000000)
|
||||
val `60` = Color(0x99000000)
|
||||
val `80` = Color(0xCC000000)
|
||||
}
|
||||
|
||||
object BaseWhite {
|
||||
val `5` = Color(0x0DFFFFFF)
|
||||
val `10` = Color(0x1AFFFFFF)
|
||||
val `15` = Color(0x26FFFFFF)
|
||||
val `20` = Color(0x33FFFFFF)
|
||||
val `25` = Color(0x40FFFFFF)
|
||||
val `30` = Color(0x4DFFFFFF)
|
||||
val `40` = Color(0x66FFFFFF)
|
||||
val `50` = Color(0x80FFFFFF)
|
||||
val `60` = Color(0x99FFFFFF)
|
||||
val `80` = Color(0xCCFFFFFF)
|
||||
}
|
||||
|
||||
object Neutral95 {
|
||||
val `5` = Color(0x0D0F0F0F)
|
||||
val `10` = Color(0x1A0F0F0F)
|
||||
val `15` = Color(0x260F0F0F)
|
||||
val `40` = Color(0x660F0F0F)
|
||||
val `60` = Color(0x990F0F0F)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,714 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
@Stable
|
||||
class TangemColors3 internal constructor(
|
||||
val text: Text,
|
||||
val bg: Bg,
|
||||
val icon: Icon,
|
||||
val border: Border,
|
||||
val overlay: Overlay,
|
||||
val interaction: Interaction,
|
||||
val material: Material,
|
||||
) {
|
||||
|
||||
@Stable
|
||||
class Text internal constructor(
|
||||
primary: Color,
|
||||
secondary: Color,
|
||||
tertiary: Color,
|
||||
brand: Color,
|
||||
val staticLight: StaticLight,
|
||||
val staticDark: StaticDark,
|
||||
val inverse: Inverse,
|
||||
val status: Status,
|
||||
val accent: Accent,
|
||||
) {
|
||||
var primary by mutableStateOf(primary)
|
||||
private set
|
||||
var secondary by mutableStateOf(secondary)
|
||||
private set
|
||||
var tertiary by mutableStateOf(tertiary)
|
||||
private set
|
||||
var brand by mutableStateOf(brand)
|
||||
private set
|
||||
|
||||
@Stable
|
||||
class StaticLight internal constructor(
|
||||
primary: Color,
|
||||
secondary: Color,
|
||||
tertiary: Color,
|
||||
) {
|
||||
var primary by mutableStateOf(primary)
|
||||
private set
|
||||
var secondary by mutableStateOf(secondary)
|
||||
private set
|
||||
var tertiary by mutableStateOf(tertiary)
|
||||
private set
|
||||
|
||||
fun update(other: StaticLight) {
|
||||
primary = other.primary
|
||||
secondary = other.secondary
|
||||
tertiary = other.tertiary
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class StaticDark internal constructor(
|
||||
primary: Color,
|
||||
secondary: Color,
|
||||
tertiary: Color,
|
||||
) {
|
||||
var primary by mutableStateOf(primary)
|
||||
private set
|
||||
var secondary by mutableStateOf(secondary)
|
||||
private set
|
||||
var tertiary by mutableStateOf(tertiary)
|
||||
private set
|
||||
|
||||
fun update(other: StaticDark) {
|
||||
primary = other.primary
|
||||
secondary = other.secondary
|
||||
tertiary = other.tertiary
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Inverse internal constructor(
|
||||
primary: Color,
|
||||
secondary: Color,
|
||||
tertiary: Color,
|
||||
) {
|
||||
var primary by mutableStateOf(primary)
|
||||
private set
|
||||
var secondary by mutableStateOf(secondary)
|
||||
private set
|
||||
var tertiary by mutableStateOf(tertiary)
|
||||
private set
|
||||
|
||||
fun update(other: Inverse) {
|
||||
primary = other.primary
|
||||
secondary = other.secondary
|
||||
tertiary = other.tertiary
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Status internal constructor(
|
||||
success: Color,
|
||||
error: Color,
|
||||
warning: Color,
|
||||
info: Color,
|
||||
) {
|
||||
var success by mutableStateOf(success)
|
||||
private set
|
||||
var error by mutableStateOf(error)
|
||||
private set
|
||||
var warning by mutableStateOf(warning)
|
||||
private set
|
||||
var info by mutableStateOf(info)
|
||||
private set
|
||||
|
||||
fun update(other: Status) {
|
||||
success = other.success
|
||||
error = other.error
|
||||
warning = other.warning
|
||||
info = other.info
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Accent internal constructor(
|
||||
blue: Color,
|
||||
violet: Color,
|
||||
red: Color,
|
||||
orange: Color,
|
||||
yellow: Color,
|
||||
green: Color,
|
||||
) {
|
||||
var blue by mutableStateOf(blue)
|
||||
private set
|
||||
var violet by mutableStateOf(violet)
|
||||
private set
|
||||
var red by mutableStateOf(red)
|
||||
private set
|
||||
var orange by mutableStateOf(orange)
|
||||
private set
|
||||
var yellow by mutableStateOf(yellow)
|
||||
private set
|
||||
var green by mutableStateOf(green)
|
||||
private set
|
||||
|
||||
fun update(other: Accent) {
|
||||
blue = other.blue
|
||||
violet = other.violet
|
||||
red = other.red
|
||||
orange = other.orange
|
||||
yellow = other.yellow
|
||||
green = other.green
|
||||
}
|
||||
}
|
||||
|
||||
fun update(other: Text) {
|
||||
primary = other.primary
|
||||
secondary = other.secondary
|
||||
tertiary = other.tertiary
|
||||
brand = other.brand
|
||||
staticLight.update(other.staticLight)
|
||||
staticDark.update(other.staticDark)
|
||||
inverse.update(other.inverse)
|
||||
status.update(other.status)
|
||||
accent.update(other.accent)
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Bg internal constructor(
|
||||
primary: Color,
|
||||
secondary: Color,
|
||||
tertiary: Color,
|
||||
brand: Color,
|
||||
inverse: Color,
|
||||
base: Color,
|
||||
disabled: Color,
|
||||
val opaque: Opaque,
|
||||
val status: Status,
|
||||
val accent: Accent,
|
||||
) {
|
||||
var primary by mutableStateOf(primary)
|
||||
private set
|
||||
var secondary by mutableStateOf(secondary)
|
||||
private set
|
||||
var tertiary by mutableStateOf(tertiary)
|
||||
private set
|
||||
var brand by mutableStateOf(brand)
|
||||
private set
|
||||
var inverse by mutableStateOf(inverse)
|
||||
private set
|
||||
var base by mutableStateOf(base)
|
||||
private set
|
||||
var disabled by mutableStateOf(disabled)
|
||||
private set
|
||||
|
||||
@Stable
|
||||
class Opaque internal constructor(
|
||||
primary: Color,
|
||||
secondary: Color,
|
||||
) {
|
||||
var primary by mutableStateOf(primary)
|
||||
private set
|
||||
var secondary by mutableStateOf(secondary)
|
||||
private set
|
||||
|
||||
fun update(other: Opaque) {
|
||||
primary = other.primary
|
||||
secondary = other.secondary
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Status internal constructor(
|
||||
success: Color,
|
||||
successSubtle: Color,
|
||||
error: Color,
|
||||
errorSubtle: Color,
|
||||
warning: Color,
|
||||
warningSubtle: Color,
|
||||
info: Color,
|
||||
infoSubtle: Color,
|
||||
) {
|
||||
var success by mutableStateOf(success)
|
||||
private set
|
||||
var successSubtle by mutableStateOf(successSubtle)
|
||||
private set
|
||||
var error by mutableStateOf(error)
|
||||
private set
|
||||
var errorSubtle by mutableStateOf(errorSubtle)
|
||||
private set
|
||||
var warning by mutableStateOf(warning)
|
||||
private set
|
||||
var warningSubtle by mutableStateOf(warningSubtle)
|
||||
private set
|
||||
var info by mutableStateOf(info)
|
||||
private set
|
||||
var infoSubtle by mutableStateOf(infoSubtle)
|
||||
private set
|
||||
|
||||
fun update(other: Status) {
|
||||
success = other.success
|
||||
successSubtle = other.successSubtle
|
||||
error = other.error
|
||||
errorSubtle = other.errorSubtle
|
||||
warning = other.warning
|
||||
warningSubtle = other.warningSubtle
|
||||
info = other.info
|
||||
infoSubtle = other.infoSubtle
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Accent internal constructor(
|
||||
blue: Color,
|
||||
violet: Color,
|
||||
red: Color,
|
||||
orange: Color,
|
||||
yellow: Color,
|
||||
green: Color,
|
||||
) {
|
||||
var blue by mutableStateOf(blue)
|
||||
private set
|
||||
var violet by mutableStateOf(violet)
|
||||
private set
|
||||
var red by mutableStateOf(red)
|
||||
private set
|
||||
var orange by mutableStateOf(orange)
|
||||
private set
|
||||
var yellow by mutableStateOf(yellow)
|
||||
private set
|
||||
var green by mutableStateOf(green)
|
||||
private set
|
||||
|
||||
fun update(other: Accent) {
|
||||
blue = other.blue
|
||||
violet = other.violet
|
||||
red = other.red
|
||||
orange = other.orange
|
||||
yellow = other.yellow
|
||||
green = other.green
|
||||
}
|
||||
}
|
||||
|
||||
fun update(other: Bg) {
|
||||
primary = other.primary
|
||||
secondary = other.secondary
|
||||
tertiary = other.tertiary
|
||||
brand = other.brand
|
||||
inverse = other.inverse
|
||||
base = other.base
|
||||
disabled = other.disabled
|
||||
opaque.update(other.opaque)
|
||||
status.update(other.status)
|
||||
accent.update(other.accent)
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Icon internal constructor(
|
||||
primary: Color,
|
||||
secondary: Color,
|
||||
tertiary: Color,
|
||||
brand: Color,
|
||||
staticLight: Color,
|
||||
staticDark: Color,
|
||||
inverse: Color,
|
||||
val status: Status,
|
||||
val accent: Accent,
|
||||
) {
|
||||
var primary by mutableStateOf(primary)
|
||||
private set
|
||||
var secondary by mutableStateOf(secondary)
|
||||
private set
|
||||
var tertiary by mutableStateOf(tertiary)
|
||||
private set
|
||||
var brand by mutableStateOf(brand)
|
||||
private set
|
||||
var staticLight by mutableStateOf(staticLight)
|
||||
private set
|
||||
var staticDark by mutableStateOf(staticDark)
|
||||
private set
|
||||
var inverse by mutableStateOf(inverse)
|
||||
private set
|
||||
|
||||
@Stable
|
||||
class Status internal constructor(
|
||||
success: Color,
|
||||
error: Color,
|
||||
warning: Color,
|
||||
info: Color,
|
||||
) {
|
||||
var success by mutableStateOf(success)
|
||||
private set
|
||||
var error by mutableStateOf(error)
|
||||
private set
|
||||
var warning by mutableStateOf(warning)
|
||||
private set
|
||||
var info by mutableStateOf(info)
|
||||
private set
|
||||
|
||||
fun update(other: Status) {
|
||||
success = other.success
|
||||
error = other.error
|
||||
warning = other.warning
|
||||
info = other.info
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Accent internal constructor(
|
||||
blue: Color,
|
||||
violet: Color,
|
||||
red: Color,
|
||||
orange: Color,
|
||||
yellow: Color,
|
||||
green: Color,
|
||||
) {
|
||||
var blue by mutableStateOf(blue)
|
||||
private set
|
||||
var violet by mutableStateOf(violet)
|
||||
private set
|
||||
var red by mutableStateOf(red)
|
||||
private set
|
||||
var orange by mutableStateOf(orange)
|
||||
private set
|
||||
var yellow by mutableStateOf(yellow)
|
||||
private set
|
||||
var green by mutableStateOf(green)
|
||||
private set
|
||||
|
||||
fun update(other: Accent) {
|
||||
blue = other.blue
|
||||
violet = other.violet
|
||||
red = other.red
|
||||
orange = other.orange
|
||||
yellow = other.yellow
|
||||
green = other.green
|
||||
}
|
||||
}
|
||||
|
||||
fun update(other: Icon) {
|
||||
primary = other.primary
|
||||
secondary = other.secondary
|
||||
tertiary = other.tertiary
|
||||
brand = other.brand
|
||||
staticLight = other.staticLight
|
||||
staticDark = other.staticDark
|
||||
inverse = other.inverse
|
||||
status.update(other.status)
|
||||
accent.update(other.accent)
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Border internal constructor(
|
||||
primary: Color,
|
||||
secondary: Color,
|
||||
tertiary: Color,
|
||||
brand: Color,
|
||||
val inverse: Inverse,
|
||||
val status: Status,
|
||||
val accent: Accent,
|
||||
) {
|
||||
var primary by mutableStateOf(primary)
|
||||
private set
|
||||
var secondary by mutableStateOf(secondary)
|
||||
private set
|
||||
var tertiary by mutableStateOf(tertiary)
|
||||
private set
|
||||
var brand by mutableStateOf(brand)
|
||||
private set
|
||||
|
||||
@Stable
|
||||
class Inverse internal constructor(
|
||||
primary: Color,
|
||||
secondary: Color,
|
||||
tertiary: Color,
|
||||
) {
|
||||
var primary by mutableStateOf(primary)
|
||||
private set
|
||||
var secondary by mutableStateOf(secondary)
|
||||
private set
|
||||
var tertiary by mutableStateOf(tertiary)
|
||||
private set
|
||||
|
||||
fun update(other: Inverse) {
|
||||
primary = other.primary
|
||||
secondary = other.secondary
|
||||
tertiary = other.tertiary
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Status internal constructor(
|
||||
success: Color,
|
||||
successSubtle: Color,
|
||||
error: Color,
|
||||
errorSubtle: Color,
|
||||
warning: Color,
|
||||
warningSubtle: Color,
|
||||
info: Color,
|
||||
infoSubtle: Color,
|
||||
) {
|
||||
var success by mutableStateOf(success)
|
||||
private set
|
||||
var successSubtle by mutableStateOf(successSubtle)
|
||||
private set
|
||||
var error by mutableStateOf(error)
|
||||
private set
|
||||
var errorSubtle by mutableStateOf(errorSubtle)
|
||||
private set
|
||||
var warning by mutableStateOf(warning)
|
||||
private set
|
||||
var warningSubtle by mutableStateOf(warningSubtle)
|
||||
private set
|
||||
var info by mutableStateOf(info)
|
||||
private set
|
||||
var infoSubtle by mutableStateOf(infoSubtle)
|
||||
private set
|
||||
|
||||
fun update(other: Status) {
|
||||
success = other.success
|
||||
successSubtle = other.successSubtle
|
||||
error = other.error
|
||||
errorSubtle = other.errorSubtle
|
||||
warning = other.warning
|
||||
warningSubtle = other.warningSubtle
|
||||
info = other.info
|
||||
infoSubtle = other.infoSubtle
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Accent internal constructor(
|
||||
blue: Color,
|
||||
violet: Color,
|
||||
red: Color,
|
||||
orange: Color,
|
||||
yellow: Color,
|
||||
green: Color,
|
||||
) {
|
||||
var blue by mutableStateOf(blue)
|
||||
private set
|
||||
var violet by mutableStateOf(violet)
|
||||
private set
|
||||
var red by mutableStateOf(red)
|
||||
private set
|
||||
var orange by mutableStateOf(orange)
|
||||
private set
|
||||
var yellow by mutableStateOf(yellow)
|
||||
private set
|
||||
var green by mutableStateOf(green)
|
||||
private set
|
||||
|
||||
fun update(other: Accent) {
|
||||
blue = other.blue
|
||||
violet = other.violet
|
||||
red = other.red
|
||||
orange = other.orange
|
||||
yellow = other.yellow
|
||||
green = other.green
|
||||
}
|
||||
}
|
||||
|
||||
fun update(other: Border) {
|
||||
primary = other.primary
|
||||
secondary = other.secondary
|
||||
tertiary = other.tertiary
|
||||
brand = other.brand
|
||||
inverse.update(other.inverse)
|
||||
status.update(other.status)
|
||||
accent.update(other.accent)
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Overlay internal constructor(
|
||||
modal: Color,
|
||||
) {
|
||||
var modal by mutableStateOf(modal)
|
||||
private set
|
||||
|
||||
fun update(other: Overlay) {
|
||||
modal = other.modal
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Interaction internal constructor(
|
||||
pressStaticLight: Color,
|
||||
pressStaticDark: Color,
|
||||
val press: Press,
|
||||
val focusRing: FocusRing,
|
||||
) {
|
||||
var pressStaticLight by mutableStateOf(pressStaticLight)
|
||||
private set
|
||||
var pressStaticDark by mutableStateOf(pressStaticDark)
|
||||
private set
|
||||
|
||||
@Stable
|
||||
class Press internal constructor(
|
||||
default: Color,
|
||||
inverse: Color,
|
||||
) {
|
||||
var default by mutableStateOf(default)
|
||||
private set
|
||||
var inverse by mutableStateOf(inverse)
|
||||
private set
|
||||
|
||||
fun update(other: Press) {
|
||||
default = other.default
|
||||
inverse = other.inverse
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class FocusRing internal constructor(
|
||||
default: Color,
|
||||
brand: Color,
|
||||
) {
|
||||
var default by mutableStateOf(default)
|
||||
private set
|
||||
var brand by mutableStateOf(brand)
|
||||
private set
|
||||
|
||||
fun update(other: FocusRing) {
|
||||
default = other.default
|
||||
brand = other.brand
|
||||
}
|
||||
}
|
||||
|
||||
fun update(other: Interaction) {
|
||||
pressStaticLight = other.pressStaticLight
|
||||
pressStaticDark = other.pressStaticDark
|
||||
press.update(other.press)
|
||||
focusRing.update(other.focusRing)
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Material internal constructor(
|
||||
val tint: Tint,
|
||||
val fill: Fill,
|
||||
val lighten: Lighten,
|
||||
val softLight: SoftLight,
|
||||
val border: Border,
|
||||
) {
|
||||
|
||||
@Stable
|
||||
class Tint internal constructor(
|
||||
glass: Color,
|
||||
blur: Color,
|
||||
solid: Color,
|
||||
) {
|
||||
var glass by mutableStateOf(glass)
|
||||
private set
|
||||
var blur by mutableStateOf(blur)
|
||||
private set
|
||||
var solid by mutableStateOf(solid)
|
||||
private set
|
||||
|
||||
fun update(other: Tint) {
|
||||
glass = other.glass
|
||||
blur = other.blur
|
||||
solid = other.solid
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Fill internal constructor(
|
||||
glass: Color,
|
||||
blur: Color,
|
||||
solid: Color,
|
||||
) {
|
||||
var glass by mutableStateOf(glass)
|
||||
private set
|
||||
var blur by mutableStateOf(blur)
|
||||
private set
|
||||
var solid by mutableStateOf(solid)
|
||||
private set
|
||||
|
||||
fun update(other: Fill) {
|
||||
glass = other.glass
|
||||
blur = other.blur
|
||||
solid = other.solid
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Lighten internal constructor(
|
||||
glass: Color,
|
||||
blur: Color,
|
||||
solid: Color,
|
||||
) {
|
||||
var glass by mutableStateOf(glass)
|
||||
private set
|
||||
var blur by mutableStateOf(blur)
|
||||
private set
|
||||
var solid by mutableStateOf(solid)
|
||||
private set
|
||||
|
||||
fun update(other: Lighten) {
|
||||
glass = other.glass
|
||||
blur = other.blur
|
||||
solid = other.solid
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class SoftLight internal constructor(
|
||||
glass: Color,
|
||||
blur: Color,
|
||||
solid: Color,
|
||||
) {
|
||||
var glass by mutableStateOf(glass)
|
||||
private set
|
||||
var blur by mutableStateOf(blur)
|
||||
private set
|
||||
var solid by mutableStateOf(solid)
|
||||
private set
|
||||
|
||||
fun update(other: SoftLight) {
|
||||
glass = other.glass
|
||||
blur = other.blur
|
||||
solid = other.solid
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Border internal constructor(
|
||||
start: Color,
|
||||
mid: Color,
|
||||
end: Color,
|
||||
) {
|
||||
var start by mutableStateOf(start)
|
||||
private set
|
||||
var mid by mutableStateOf(mid)
|
||||
private set
|
||||
var end by mutableStateOf(end)
|
||||
private set
|
||||
|
||||
fun update(other: Border) {
|
||||
start = other.start
|
||||
mid = other.mid
|
||||
end = other.end
|
||||
}
|
||||
}
|
||||
|
||||
fun update(other: Material) {
|
||||
tint.update(other.tint)
|
||||
fill.update(other.fill)
|
||||
lighten.update(other.lighten)
|
||||
softLight.update(other.softLight)
|
||||
border.update(other.border)
|
||||
}
|
||||
}
|
||||
|
||||
fun update(other: TangemColors3) {
|
||||
text.update(other.text)
|
||||
bg.update(other.bg)
|
||||
icon.update(other.icon)
|
||||
border.update(other.border)
|
||||
overlay.update(other.overlay)
|
||||
interaction.update(other.interaction)
|
||||
material.update(other.material)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
* Theme: Dark
|
||||
*/
|
||||
internal fun darkColors3() =
|
||||
TangemColors3(
|
||||
text = TangemColors3.Text(
|
||||
primary = TangemColorPalette.Base.white,
|
||||
secondary = TangemColorPalette.Opaque.BaseWhite.`60`,
|
||||
tertiary = TangemColorPalette.Opaque.BaseWhite.`30`,
|
||||
brand = TangemColorPalette.Blue.`50`,
|
||||
staticLight = TangemColors3.Text.StaticLight(
|
||||
primary = TangemColorPalette.Base.black,
|
||||
secondary = TangemColorPalette.Opaque.BaseBlack.`60`,
|
||||
tertiary = TangemColorPalette.Opaque.BaseBlack.`40`,
|
||||
),
|
||||
staticDark = TangemColors3.Text.StaticDark(
|
||||
primary = TangemColorPalette.Base.white,
|
||||
secondary = TangemColorPalette.Opaque.BaseWhite.`60`,
|
||||
tertiary = TangemColorPalette.Opaque.BaseWhite.`30`,
|
||||
),
|
||||
inverse = TangemColors3.Text.Inverse(
|
||||
primary = TangemColorPalette.Neutral.`95`,
|
||||
secondary = TangemColorPalette.Opaque.Neutral95.`60`,
|
||||
tertiary = TangemColorPalette.Opaque.Neutral95.`40`,
|
||||
),
|
||||
status = TangemColors3.Text.Status(
|
||||
success = TangemColorPalette.Green.`40`,
|
||||
error = TangemColorPalette.Red.`40`,
|
||||
warning = TangemColorPalette.Yellow.`40`,
|
||||
info = TangemColorPalette.Blue.`40`,
|
||||
),
|
||||
accent = TangemColors3.Text.Accent(
|
||||
blue = TangemColorPalette.Blue.`40`,
|
||||
violet = TangemColorPalette.Violet.`40`,
|
||||
red = TangemColorPalette.Red.`40`,
|
||||
orange = TangemColorPalette.Orange.`40`,
|
||||
yellow = TangemColorPalette.Yellow.`40`,
|
||||
green = TangemColorPalette.Green.`40`,
|
||||
),
|
||||
),
|
||||
bg = TangemColors3.Bg(
|
||||
primary = TangemColorPalette.Neutral.`95`,
|
||||
secondary = TangemColorPalette.Neutral.`90`,
|
||||
tertiary = TangemColorPalette.Neutral.`80`,
|
||||
brand = TangemColorPalette.Blue.`50`,
|
||||
inverse = TangemColorPalette.Neutral.`5`,
|
||||
base = TangemColorPalette.Base.black,
|
||||
disabled = TangemColorPalette.Neutral.`70`,
|
||||
opaque = TangemColors3.Bg.Opaque(
|
||||
primary = TangemColorPalette.Opaque.BaseWhite.`5`,
|
||||
secondary = TangemColorPalette.Opaque.BaseWhite.`10`,
|
||||
),
|
||||
status = TangemColors3.Bg.Status(
|
||||
success = TangemColorPalette.Green.`50`,
|
||||
successSubtle = TangemColorPalette.Green.`90`,
|
||||
error = TangemColorPalette.Red.`50`,
|
||||
errorSubtle = TangemColorPalette.Red.`90`,
|
||||
warning = TangemColorPalette.Yellow.`50`,
|
||||
warningSubtle = TangemColorPalette.Yellow.`90`,
|
||||
info = TangemColorPalette.Blue.`50`,
|
||||
infoSubtle = TangemColorPalette.Blue.`90`,
|
||||
),
|
||||
accent = TangemColors3.Bg.Accent(
|
||||
blue = TangemColorPalette.Blue.`50`,
|
||||
violet = TangemColorPalette.Violet.`50`,
|
||||
red = TangemColorPalette.Red.`50`,
|
||||
orange = TangemColorPalette.Orange.`50`,
|
||||
yellow = TangemColorPalette.Yellow.`50`,
|
||||
green = TangemColorPalette.Green.`50`,
|
||||
),
|
||||
),
|
||||
icon = TangemColors3.Icon(
|
||||
primary = TangemColorPalette.Base.white,
|
||||
secondary = TangemColorPalette.Opaque.BaseWhite.`60`,
|
||||
tertiary = TangemColorPalette.Opaque.BaseWhite.`30`,
|
||||
brand = TangemColorPalette.Blue.`50`,
|
||||
staticLight = TangemColorPalette.Base.black,
|
||||
staticDark = TangemColorPalette.Base.white,
|
||||
inverse = TangemColorPalette.Neutral.`95`,
|
||||
status = TangemColors3.Icon.Status(
|
||||
success = TangemColorPalette.Green.`40`,
|
||||
error = TangemColorPalette.Red.`40`,
|
||||
warning = TangemColorPalette.Yellow.`40`,
|
||||
info = TangemColorPalette.Blue.`40`,
|
||||
),
|
||||
accent = TangemColors3.Icon.Accent(
|
||||
blue = TangemColorPalette.Blue.`40`,
|
||||
violet = TangemColorPalette.Violet.`40`,
|
||||
red = TangemColorPalette.Red.`40`,
|
||||
orange = TangemColorPalette.Orange.`40`,
|
||||
yellow = TangemColorPalette.Yellow.`40`,
|
||||
green = TangemColorPalette.Green.`40`,
|
||||
),
|
||||
),
|
||||
border = TangemColors3.Border(
|
||||
primary = TangemColorPalette.Opaque.BaseWhite.`5`,
|
||||
secondary = TangemColorPalette.Opaque.BaseWhite.`10`,
|
||||
tertiary = TangemColorPalette.Opaque.BaseWhite.`20`,
|
||||
brand = TangemColorPalette.Blue.`50`,
|
||||
inverse = TangemColors3.Border.Inverse(
|
||||
primary = TangemColorPalette.Opaque.BaseBlack.`5`,
|
||||
secondary = TangemColorPalette.Opaque.BaseBlack.`10`,
|
||||
tertiary = TangemColorPalette.Opaque.BaseBlack.`20`,
|
||||
),
|
||||
status = TangemColors3.Border.Status(
|
||||
success = TangemColorPalette.Green.`40`,
|
||||
successSubtle = TangemColorPalette.Green.`80`,
|
||||
error = TangemColorPalette.Red.`40`,
|
||||
errorSubtle = TangemColorPalette.Red.`80`,
|
||||
warning = TangemColorPalette.Yellow.`40`,
|
||||
warningSubtle = TangemColorPalette.Yellow.`80`,
|
||||
info = TangemColorPalette.Blue.`40`,
|
||||
infoSubtle = TangemColorPalette.Blue.`80`,
|
||||
),
|
||||
accent = TangemColors3.Border.Accent(
|
||||
blue = TangemColorPalette.Blue.`40`,
|
||||
violet = TangemColorPalette.Violet.`40`,
|
||||
red = TangemColorPalette.Red.`40`,
|
||||
orange = TangemColorPalette.Orange.`40`,
|
||||
yellow = TangemColorPalette.Yellow.`40`,
|
||||
green = TangemColorPalette.Green.`40`,
|
||||
),
|
||||
),
|
||||
overlay = TangemColors3.Overlay(
|
||||
modal = TangemColorPalette.Opaque.BaseBlack.`80`,
|
||||
),
|
||||
interaction = TangemColors3.Interaction(
|
||||
pressStaticLight = TangemColorPalette.Opaque.BaseBlack.`10`,
|
||||
pressStaticDark = TangemColorPalette.Opaque.BaseWhite.`10`,
|
||||
press = TangemColors3.Interaction.Press(
|
||||
default = TangemColorPalette.Opaque.BaseWhite.`10`,
|
||||
inverse = TangemColorPalette.Opaque.BaseBlack.`10`,
|
||||
),
|
||||
focusRing = TangemColors3.Interaction.FocusRing(
|
||||
default = TangemColorPalette.Neutral.`5`,
|
||||
brand = TangemColorPalette.Blue.`50`,
|
||||
),
|
||||
),
|
||||
material = TangemColors3.Material(
|
||||
tint = TangemColors3.Material.Tint(
|
||||
glass = Color(0x662C2C2C),
|
||||
blur = Color(0x00000000),
|
||||
solid = Color(0x1AFFFFFF),
|
||||
),
|
||||
fill = TangemColors3.Material.Fill(
|
||||
glass = Color(0x00000000),
|
||||
blur = Color(0x1AFFFFFF),
|
||||
solid = Color(0xE62C2C2C),
|
||||
),
|
||||
lighten = TangemColors3.Material.Lighten(
|
||||
glass = Color(0x33181818),
|
||||
blur = Color(0x00000000),
|
||||
solid = Color(0x00000000),
|
||||
),
|
||||
softLight = TangemColors3.Material.SoftLight(
|
||||
glass = Color(0x1A000000),
|
||||
blur = Color(0x00000000),
|
||||
solid = Color(0x00000000),
|
||||
),
|
||||
border = TangemColors3.Material.Border(
|
||||
start = Color(0x33FFFFFF),
|
||||
mid = Color(0x00FFFFFF),
|
||||
end = Color(0x1AFFFFFF),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
* Theme: Light
|
||||
*/
|
||||
internal fun lightColors3() =
|
||||
TangemColors3(
|
||||
text = TangemColors3.Text(
|
||||
primary = TangemColorPalette.Neutral.`95`,
|
||||
secondary = TangemColorPalette.Opaque.Neutral95.`60`,
|
||||
tertiary = TangemColorPalette.Opaque.Neutral95.`40`,
|
||||
brand = TangemColorPalette.Blue.`50`,
|
||||
staticLight = TangemColors3.Text.StaticLight(
|
||||
primary = TangemColorPalette.Base.black,
|
||||
secondary = TangemColorPalette.Opaque.BaseBlack.`60`,
|
||||
tertiary = TangemColorPalette.Opaque.BaseBlack.`40`,
|
||||
),
|
||||
staticDark = TangemColors3.Text.StaticDark(
|
||||
primary = TangemColorPalette.Base.white,
|
||||
secondary = TangemColorPalette.Opaque.BaseWhite.`60`,
|
||||
tertiary = TangemColorPalette.Opaque.BaseWhite.`30`,
|
||||
),
|
||||
inverse = TangemColors3.Text.Inverse(
|
||||
primary = TangemColorPalette.Base.white,
|
||||
secondary = TangemColorPalette.Opaque.BaseWhite.`60`,
|
||||
tertiary = TangemColorPalette.Opaque.BaseWhite.`30`,
|
||||
),
|
||||
status = TangemColors3.Text.Status(
|
||||
success = TangemColorPalette.Green.`50`,
|
||||
error = TangemColorPalette.Red.`50`,
|
||||
warning = TangemColorPalette.Yellow.`50`,
|
||||
info = TangemColorPalette.Blue.`50`,
|
||||
),
|
||||
accent = TangemColors3.Text.Accent(
|
||||
blue = TangemColorPalette.Blue.`50`,
|
||||
violet = TangemColorPalette.Violet.`50`,
|
||||
red = TangemColorPalette.Red.`50`,
|
||||
orange = TangemColorPalette.Orange.`50`,
|
||||
yellow = TangemColorPalette.Yellow.`50`,
|
||||
green = TangemColorPalette.Green.`50`,
|
||||
),
|
||||
),
|
||||
bg = TangemColors3.Bg(
|
||||
primary = TangemColorPalette.Neutral.`5`,
|
||||
secondary = TangemColorPalette.Base.white,
|
||||
tertiary = TangemColorPalette.Neutral.`10`,
|
||||
brand = TangemColorPalette.Blue.`50`,
|
||||
inverse = TangemColorPalette.Neutral.`95`,
|
||||
base = TangemColorPalette.Neutral.`5`,
|
||||
disabled = TangemColorPalette.Neutral.`20`,
|
||||
opaque = TangemColors3.Bg.Opaque(
|
||||
primary = TangemColorPalette.Opaque.Neutral95.`5`,
|
||||
secondary = TangemColorPalette.Opaque.Neutral95.`10`,
|
||||
),
|
||||
status = TangemColors3.Bg.Status(
|
||||
success = TangemColorPalette.Green.`50`,
|
||||
successSubtle = TangemColorPalette.Green.`10`,
|
||||
error = TangemColorPalette.Red.`50`,
|
||||
errorSubtle = TangemColorPalette.Red.`10`,
|
||||
warning = TangemColorPalette.Yellow.`50`,
|
||||
warningSubtle = TangemColorPalette.Yellow.`10`,
|
||||
info = TangemColorPalette.Blue.`50`,
|
||||
infoSubtle = TangemColorPalette.Blue.`10`,
|
||||
),
|
||||
accent = TangemColors3.Bg.Accent(
|
||||
blue = TangemColorPalette.Blue.`50`,
|
||||
violet = TangemColorPalette.Violet.`50`,
|
||||
red = TangemColorPalette.Red.`50`,
|
||||
orange = TangemColorPalette.Orange.`50`,
|
||||
yellow = TangemColorPalette.Yellow.`50`,
|
||||
green = TangemColorPalette.Green.`50`,
|
||||
),
|
||||
),
|
||||
icon = TangemColors3.Icon(
|
||||
primary = TangemColorPalette.Neutral.`95`,
|
||||
secondary = TangemColorPalette.Opaque.Neutral95.`60`,
|
||||
tertiary = TangemColorPalette.Opaque.Neutral95.`40`,
|
||||
brand = TangemColorPalette.Blue.`50`,
|
||||
staticLight = TangemColorPalette.Base.black,
|
||||
staticDark = TangemColorPalette.Base.white,
|
||||
inverse = TangemColorPalette.Base.white,
|
||||
status = TangemColors3.Icon.Status(
|
||||
success = TangemColorPalette.Green.`50`,
|
||||
error = TangemColorPalette.Red.`50`,
|
||||
warning = TangemColorPalette.Yellow.`50`,
|
||||
info = TangemColorPalette.Blue.`50`,
|
||||
),
|
||||
accent = TangemColors3.Icon.Accent(
|
||||
blue = TangemColorPalette.Blue.`50`,
|
||||
violet = TangemColorPalette.Violet.`50`,
|
||||
red = TangemColorPalette.Red.`50`,
|
||||
orange = TangemColorPalette.Orange.`50`,
|
||||
yellow = TangemColorPalette.Yellow.`50`,
|
||||
green = TangemColorPalette.Green.`50`,
|
||||
),
|
||||
),
|
||||
border = TangemColors3.Border(
|
||||
primary = TangemColorPalette.Opaque.BaseBlack.`5`,
|
||||
secondary = TangemColorPalette.Opaque.BaseBlack.`10`,
|
||||
tertiary = TangemColorPalette.Opaque.BaseBlack.`20`,
|
||||
brand = TangemColorPalette.Blue.`50`,
|
||||
inverse = TangemColors3.Border.Inverse(
|
||||
primary = TangemColorPalette.Opaque.BaseWhite.`5`,
|
||||
secondary = TangemColorPalette.Opaque.BaseWhite.`10`,
|
||||
tertiary = TangemColorPalette.Opaque.BaseWhite.`20`,
|
||||
),
|
||||
status = TangemColors3.Border.Status(
|
||||
success = TangemColorPalette.Green.`50`,
|
||||
successSubtle = TangemColorPalette.Green.`20`,
|
||||
error = TangemColorPalette.Red.`50`,
|
||||
errorSubtle = TangemColorPalette.Red.`20`,
|
||||
warning = TangemColorPalette.Yellow.`50`,
|
||||
warningSubtle = TangemColorPalette.Yellow.`20`,
|
||||
info = TangemColorPalette.Blue.`50`,
|
||||
infoSubtle = TangemColorPalette.Blue.`20`,
|
||||
),
|
||||
accent = TangemColors3.Border.Accent(
|
||||
blue = TangemColorPalette.Blue.`50`,
|
||||
violet = TangemColorPalette.Violet.`50`,
|
||||
red = TangemColorPalette.Red.`50`,
|
||||
orange = TangemColorPalette.Orange.`50`,
|
||||
yellow = TangemColorPalette.Yellow.`50`,
|
||||
green = TangemColorPalette.Green.`50`,
|
||||
),
|
||||
),
|
||||
overlay = TangemColors3.Overlay(
|
||||
modal = TangemColorPalette.Opaque.BaseBlack.`60`,
|
||||
),
|
||||
interaction = TangemColors3.Interaction(
|
||||
pressStaticLight = TangemColorPalette.Opaque.BaseBlack.`10`,
|
||||
pressStaticDark = TangemColorPalette.Opaque.BaseWhite.`10`,
|
||||
press = TangemColors3.Interaction.Press(
|
||||
default = TangemColorPalette.Opaque.BaseBlack.`10`,
|
||||
inverse = TangemColorPalette.Opaque.BaseWhite.`10`,
|
||||
),
|
||||
focusRing = TangemColors3.Interaction.FocusRing(
|
||||
default = TangemColorPalette.Neutral.`95`,
|
||||
brand = TangemColorPalette.Blue.`50`,
|
||||
),
|
||||
),
|
||||
material = TangemColors3.Material(
|
||||
tint = TangemColors3.Material.Tint(
|
||||
glass = Color(0x00000000),
|
||||
blur = Color(0x00000000),
|
||||
solid = Color(0x1AFFFFFF),
|
||||
),
|
||||
fill = TangemColors3.Material.Fill(
|
||||
glass = Color(0x00000000),
|
||||
blur = Color(0x99FFFFFF),
|
||||
solid = Color(0xE6FFFFFF),
|
||||
),
|
||||
lighten = TangemColors3.Material.Lighten(
|
||||
glass = Color(0x80F7F7F7),
|
||||
blur = Color(0x00000000),
|
||||
solid = Color(0x00000000),
|
||||
),
|
||||
softLight = TangemColors3.Material.SoftLight(
|
||||
glass = Color(0x33000000),
|
||||
blur = Color(0x00000000),
|
||||
solid = Color(0x00000000),
|
||||
),
|
||||
border = TangemColors3.Material.Border(
|
||||
start = Color(0x26000000),
|
||||
mid = Color(0x00000000),
|
||||
end = Color(0x1A000000),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
package com.tangem.core.ui.res.generated
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
* Theme: Dark
|
||||
*/
|
||||
internal class TangemDarkColorTokens {
|
||||
// color.text
|
||||
val colorTextPrimary = Color(0xFFFFFFFF)
|
||||
val colorTextSecondary = Color(0x99FFFFFF)
|
||||
val colorTextTertiary = Color(0x4DFFFFFF)
|
||||
val colorTextBrand = Color(0xFF0090F9)
|
||||
val colorTextStaticLightPrimary = Color(0xFF000000)
|
||||
val colorTextStaticLightSecondary = Color(0x99000000)
|
||||
val colorTextStaticLightTertiary = Color(0x66000000)
|
||||
val colorTextStaticDarkPrimary = Color(0xFFFFFFFF)
|
||||
val colorTextStaticDarkSecondary = Color(0x99FFFFFF)
|
||||
val colorTextStaticDarkTertiary = Color(0x4DFFFFFF)
|
||||
val colorTextInversePrimary = Color(0xFF0F0F0F)
|
||||
val colorTextInverseSecondary = Color(0x990F0F0F)
|
||||
val colorTextInverseTertiary = Color(0x660F0F0F)
|
||||
val colorTextStatusSuccess = Color(0xFF2DAE3B)
|
||||
val colorTextStatusError = Color(0xFFFF5E66)
|
||||
val colorTextStatusWarning = Color(0xFFEFA210)
|
||||
val colorTextStatusInfo = Color(0xFF109FF0)
|
||||
val colorTextAccentBlue = Color(0xFF109FF0)
|
||||
val colorTextAccentViolet = Color(0xFFB07BFD)
|
||||
val colorTextAccentRed = Color(0xFFFF5E66)
|
||||
val colorTextAccentOrange = Color(0xFFFA6931)
|
||||
val colorTextAccentYellow = Color(0xFFEFA210)
|
||||
val colorTextAccentGreen = Color(0xFF2DAE3B)
|
||||
|
||||
// color.bg
|
||||
val colorBgPrimary = Color(0xFF0F0F0F)
|
||||
val colorBgSecondary = Color(0xFF1B1B1B)
|
||||
val colorBgTertiary = Color(0xFF2C2C2C)
|
||||
val colorBgBrand = Color(0xFF0090F9)
|
||||
val colorBgInverse = Color(0xFFF4F4F4)
|
||||
val colorBgBase = Color(0xFF000000)
|
||||
val colorBgOpaquePrimary = Color(0x0DFFFFFF)
|
||||
val colorBgOpaqueSecondary = Color(0x1AFFFFFF)
|
||||
val colorBgStatusSuccess = Color(0xFF2DA30D)
|
||||
val colorBgStatusError = Color(0xFFF25508)
|
||||
val colorBgStatusWarning = Color(0xFFE68A03)
|
||||
val colorBgStatusInfo = Color(0xFF0090F9)
|
||||
val colorBgAccentBlue = Color(0xFF0090F9)
|
||||
val colorBgAccentViolet = Color(0xFFA967FD)
|
||||
val colorBgAccentRed = Color(0xFFFE4142)
|
||||
val colorBgAccentOrange = Color(0xFFF25508)
|
||||
val colorBgAccentYellow = Color(0xFFE68A03)
|
||||
val colorBgAccentGreen = Color(0xFF2DA30D)
|
||||
|
||||
// color.icon
|
||||
val colorIconPrimary = Color(0xFFFFFFFF)
|
||||
val colorIconSecondary = Color(0x99FFFFFF)
|
||||
val colorIconTertiary = Color(0x4DFFFFFF)
|
||||
val colorIconBrand = Color(0xFF0090F9)
|
||||
val colorIconStaticLight = Color(0xFF000000)
|
||||
val colorIconStaticDark = Color(0xFFFFFFFF)
|
||||
val colorIconInverse = Color(0xFF0F0F0F)
|
||||
val colorIconStatusSuccess = Color(0xFF2DAE3B)
|
||||
val colorIconStatusError = Color(0xFFFA6931)
|
||||
val colorIconStatusWarning = Color(0xFFEFA210)
|
||||
val colorIconStatusInfo = Color(0xFF109FF0)
|
||||
val colorIconAccentBlue = Color(0xFF109FF0)
|
||||
val colorIconAccentViolet = Color(0xFFB07BFD)
|
||||
val colorIconAccentRed = Color(0xFFFF5E66)
|
||||
val colorIconAccentOrange = Color(0xFFFA6931)
|
||||
val colorIconAccentYellow = Color(0xFFEFA210)
|
||||
val colorIconAccentGreen = Color(0xFF2DAE3B)
|
||||
|
||||
// color.border
|
||||
val colorBorderPrimary = Color(0x0DFFFFFF)
|
||||
val colorBorderSecondary = Color(0x1AFFFFFF)
|
||||
val colorBorderTertiary = Color(0x33FFFFFF)
|
||||
val colorBorderBrand = Color(0xFF0090F9)
|
||||
val colorBorderInversePrimary = Color(0x0D000000)
|
||||
val colorBorderInverseSecondary = Color(0x1A000000)
|
||||
val colorBorderInverseTertiary = Color(0x33000000)
|
||||
val colorBorderStatusSuccess = Color(0xFF2DAE3B)
|
||||
val colorBorderStatusError = Color(0xFFFA6931)
|
||||
val colorBorderStatusWarning = Color(0xFFEFA210)
|
||||
val colorBorderStatusInfo = Color(0xFF109FF0)
|
||||
val colorBorderAccentBlue = Color(0xFF109FF0)
|
||||
val colorBorderAccentViolet = Color(0xFFB07BFD)
|
||||
val colorBorderAccentRed = Color(0xFFFF5E66)
|
||||
val colorBorderAccentOrange = Color(0xFFFA6931)
|
||||
val colorBorderAccentYellow = Color(0xFFEFA210)
|
||||
val colorBorderAccentGreen = Color(0xFF2DAE3B)
|
||||
|
||||
// color.overlay
|
||||
val colorOverlayModal = Color(0xCC000000)
|
||||
|
||||
// color.interaction
|
||||
val colorInteractionPress = Color(0x1AFFFFFF)
|
||||
val colorInteractionPressStaticLight = Color(0x1A000000)
|
||||
val colorInteractionPressStaticDark = Color(0x1AFFFFFF)
|
||||
val colorInteractionPressInverse = Color(0x1A000000)
|
||||
|
||||
// color.material
|
||||
val colorMaterialTintGlass = Color(0x66181818)
|
||||
val colorMaterialTintBlur = Color(0x00000000)
|
||||
val colorMaterialTintSolid = Color(0x1AFFFFFF)
|
||||
val colorMaterialFillGlass = Color(0x00000000)
|
||||
val colorMaterialFillBlur = Color(0x1AFFFFFF)
|
||||
val colorMaterialFillSolid = Color(0xE62C2C2C)
|
||||
val colorMaterialLightenGlass = Color(0x33181818)
|
||||
val colorMaterialLightenBlur = Color(0x00000000)
|
||||
val colorMaterialLightenSolid = Color(0x00000000)
|
||||
val colorMaterialSoftLightGlass = Color(0x1A000000)
|
||||
val colorMaterialSoftLightBlur = Color(0x00000000)
|
||||
val colorMaterialSoftLightSolid = Color(0x00000000)
|
||||
val colorMaterialBorderStart = Color(0x33FFFFFF)
|
||||
val colorMaterialBorderMid = Color(0x00FFFFFF)
|
||||
val colorMaterialBorderEnd = Color(0x1AFFFFFF)
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
@Stable
|
||||
class TangemDimens3 internal constructor(
|
||||
val opacity: Opacity = Opacity(),
|
||||
val blur: Blur = Blur(),
|
||||
val borderRadius: BorderRadius = BorderRadius(),
|
||||
val borderWidth: BorderWidth = BorderWidth(),
|
||||
val size: Size = Size(),
|
||||
val spacing: Spacing = Spacing(),
|
||||
) {
|
||||
@Stable
|
||||
class Opacity internal constructor(
|
||||
val disabled: Float = 0.4f,
|
||||
)
|
||||
|
||||
@Stable
|
||||
class Blur internal constructor(
|
||||
val card: Dp = 48.dp,
|
||||
val Button: Dp = 32.dp,
|
||||
)
|
||||
|
||||
@Stable
|
||||
class BorderRadius internal constructor(
|
||||
val b100: Dp = 8.dp,
|
||||
val b150: Dp = 12.dp,
|
||||
val b200: Dp = 16.dp,
|
||||
val b250: Dp = 20.dp,
|
||||
val b300: Dp = 24.dp,
|
||||
val b400: Dp = 32.dp,
|
||||
val none: Dp = 0.dp,
|
||||
val b075: Dp = 6.dp,
|
||||
val b050: Dp = 4.dp,
|
||||
val full: Dp = 999.dp,
|
||||
)
|
||||
|
||||
@Stable
|
||||
class BorderWidth internal constructor(
|
||||
val none: Dp = 0.dp,
|
||||
val xs: Dp = 0.5.dp,
|
||||
val sm: Dp = 1.dp,
|
||||
val md: Dp = 2.dp,
|
||||
val lg: Dp = 4.dp,
|
||||
)
|
||||
|
||||
@Stable
|
||||
class Size internal constructor(
|
||||
val s100: Dp = 8.dp,
|
||||
val s125: Dp = 10.dp,
|
||||
val s150: Dp = 12.dp,
|
||||
val s200: Dp = 16.dp,
|
||||
val s250: Dp = 20.dp,
|
||||
val s300: Dp = 24.dp,
|
||||
val s350: Dp = 28.dp,
|
||||
val s400: Dp = 32.dp,
|
||||
val s450: Dp = 36.dp,
|
||||
val s500: Dp = 40.dp,
|
||||
val s550: Dp = 44.dp,
|
||||
val s600: Dp = 48.dp,
|
||||
val s700: Dp = 56.dp,
|
||||
val s800: Dp = 64.dp,
|
||||
val s900: Dp = 72.dp,
|
||||
val s1000: Dp = 80.dp,
|
||||
val s1100: Dp = 88.dp,
|
||||
val s1200: Dp = 96.dp,
|
||||
val s025: Dp = 2.dp,
|
||||
val s050: Dp = 4.dp,
|
||||
val card: Card = Card(),
|
||||
) {
|
||||
@Stable
|
||||
class Card internal constructor(
|
||||
val sm: Dp = 128.dp,
|
||||
)
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Spacing internal constructor(
|
||||
val s100: Dp = 8.dp,
|
||||
val s125: Dp = 10.dp,
|
||||
val s150: Dp = 12.dp,
|
||||
val s200: Dp = 16.dp,
|
||||
val s250: Dp = 20.dp,
|
||||
val s300: Dp = 24.dp,
|
||||
val s350: Dp = 28.dp,
|
||||
val s400: Dp = 32.dp,
|
||||
val s450: Dp = 36.dp,
|
||||
val s500: Dp = 40.dp,
|
||||
val s550: Dp = 44.dp,
|
||||
val s600: Dp = 48.dp,
|
||||
val s700: Dp = 56.dp,
|
||||
val s800: Dp = 64.dp,
|
||||
val s900: Dp = 72.dp,
|
||||
val s1000: Dp = 80.dp,
|
||||
val s025: Dp = 2.dp,
|
||||
val s050: Dp = 4.dp,
|
||||
val s075: Dp = 6.dp,
|
||||
val none: Dp = 0.dp,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
package com.tangem.core.ui.res.generated
|
||||
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
internal class TangemDimensionTokens {
|
||||
// blur
|
||||
val blurSizeCard = 48.dp
|
||||
val blurSizeButton = 32.dp
|
||||
|
||||
// border-radius
|
||||
val borderRadius100 = 8.dp
|
||||
val borderRadius150 = 12.dp
|
||||
val borderRadius200 = 16.dp
|
||||
val borderRadius250 = 20.dp
|
||||
val borderRadius300 = 24.dp
|
||||
val borderRadius400 = 32.dp
|
||||
val borderRadiusNone = 0.dp
|
||||
val borderRadius075 = 6.dp
|
||||
val borderRadius050 = 4.dp
|
||||
val borderRadiusFull = 999.dp
|
||||
|
||||
// border-width
|
||||
val borderWidthNone = 0.dp
|
||||
val borderWidthXs = 0.5.dp
|
||||
val borderWidthSm = 1.dp
|
||||
val borderWidthMd = 2.dp
|
||||
val borderWidthLg = 4.dp
|
||||
|
||||
// size
|
||||
val size100 = 8.dp
|
||||
val size125 = 10.dp
|
||||
val size150 = 12.dp
|
||||
val size200 = 16.dp
|
||||
val size250 = 20.dp
|
||||
val size300 = 24.dp
|
||||
val size350 = 28.dp
|
||||
val size400 = 32.dp
|
||||
val size450 = 36.dp
|
||||
val size500 = 40.dp
|
||||
val size550 = 44.dp
|
||||
val size600 = 48.dp
|
||||
val size700 = 56.dp
|
||||
val size800 = 64.dp
|
||||
val size1000 = 80.dp
|
||||
val size1100 = 88.dp
|
||||
val size1200 = 96.dp
|
||||
val size025 = 2.dp
|
||||
val size050 = 4.dp
|
||||
val sizeCardSm = 128.dp
|
||||
|
||||
// spacing
|
||||
val spacing100 = 8.dp
|
||||
val spacing150 = 12.dp
|
||||
val spacing200 = 16.dp
|
||||
val spacing250 = 20.dp
|
||||
val spacing300 = 24.dp
|
||||
val spacing350 = 28.dp
|
||||
val spacing400 = 32.dp
|
||||
val spacing450 = 36.dp
|
||||
val spacing500 = 40.dp
|
||||
val spacing550 = 44.dp
|
||||
val spacing600 = 48.dp
|
||||
val spacing700 = 56.dp
|
||||
val spacing800 = 64.dp
|
||||
val spacing1000 = 80.dp
|
||||
val spacing025 = 2.dp
|
||||
val spacing050 = 4.dp
|
||||
val spacingNone = 0.dp
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
package com.tangem.core.ui.res.generated
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
* Theme: Light
|
||||
*/
|
||||
internal class TangemLightColorTokens {
|
||||
// color.text
|
||||
val colorTextPrimary = Color(0xFF0F0F0F)
|
||||
val colorTextSecondary = Color(0x990F0F0F)
|
||||
val colorTextTertiary = Color(0x660F0F0F)
|
||||
val colorTextBrand = Color(0xFF0090F9)
|
||||
val colorTextStaticLightPrimary = Color(0xFF000000)
|
||||
val colorTextStaticLightSecondary = Color(0x99000000)
|
||||
val colorTextStaticLightTertiary = Color(0x66000000)
|
||||
val colorTextStaticDarkPrimary = Color(0xFFFFFFFF)
|
||||
val colorTextStaticDarkSecondary = Color(0x99FFFFFF)
|
||||
val colorTextStaticDarkTertiary = Color(0x4DFFFFFF)
|
||||
val colorTextInversePrimary = Color(0xFFFFFFFF)
|
||||
val colorTextInverseSecondary = Color(0x99FFFFFF)
|
||||
val colorTextInverseTertiary = Color(0x4DFFFFFF)
|
||||
val colorTextStatusSuccess = Color(0xFF2DA30D)
|
||||
val colorTextStatusError = Color(0xFFFE4142)
|
||||
val colorTextStatusWarning = Color(0xFFE68A03)
|
||||
val colorTextStatusInfo = Color(0xFF0090F9)
|
||||
val colorTextAccentBlue = Color(0xFF0090F9)
|
||||
val colorTextAccentViolet = Color(0xFFA967FD)
|
||||
val colorTextAccentRed = Color(0xFFFE4142)
|
||||
val colorTextAccentOrange = Color(0xFFF25508)
|
||||
val colorTextAccentYellow = Color(0xFFE68A03)
|
||||
val colorTextAccentGreen = Color(0xFF2DA30D)
|
||||
|
||||
// color.bg
|
||||
val colorBgPrimary = Color(0xFFF4F4F4)
|
||||
val colorBgSecondary = Color(0xFFFFFFFF)
|
||||
val colorBgTertiary = Color(0xFFEAEAEA)
|
||||
val colorBgBrand = Color(0xFF0090F9)
|
||||
val colorBgInverse = Color(0xFFF4F4F4)
|
||||
val colorBgBase = Color(0xFFF4F4F4)
|
||||
val colorBgOpaquePrimary = Color(0x0DFFFFFF)
|
||||
val colorBgOpaqueSecondary = Color(0x1AFFFFFF)
|
||||
val colorBgStatusSuccess = Color(0xFF2DA30D)
|
||||
val colorBgStatusError = Color(0xFFF25508)
|
||||
val colorBgStatusWarning = Color(0xFFE68A03)
|
||||
val colorBgStatusInfo = Color(0xFF0090F9)
|
||||
val colorBgAccentBlue = Color(0xFF0090F9)
|
||||
val colorBgAccentViolet = Color(0xFFA967FD)
|
||||
val colorBgAccentRed = Color(0xFFFE4142)
|
||||
val colorBgAccentOrange = Color(0xFFF25508)
|
||||
val colorBgAccentYellow = Color(0xFFE68A03)
|
||||
val colorBgAccentGreen = Color(0xFF2DA30D)
|
||||
|
||||
// color.icon
|
||||
val colorIconPrimary = Color(0xFF0F0F0F)
|
||||
val colorIconSecondary = Color(0x990F0F0F)
|
||||
val colorIconTertiary = Color(0x660F0F0F)
|
||||
val colorIconBrand = Color(0xFF0090F9)
|
||||
val colorIconStaticLight = Color(0xFF000000)
|
||||
val colorIconStaticDark = Color(0xFFFFFFFF)
|
||||
val colorIconInverse = Color(0xFFFFFFFF)
|
||||
val colorIconStatusSuccess = Color(0xFF2DA30D)
|
||||
val colorIconStatusError = Color(0xFFF25508)
|
||||
val colorIconStatusWarning = Color(0xFFE68A03)
|
||||
val colorIconStatusInfo = Color(0xFF0090F9)
|
||||
val colorIconAccentBlue = Color(0xFF0090F9)
|
||||
val colorIconAccentViolet = Color(0xFFA967FD)
|
||||
val colorIconAccentRed = Color(0xFFFE4142)
|
||||
val colorIconAccentOrange = Color(0xFFF25508)
|
||||
val colorIconAccentYellow = Color(0xFFE68A03)
|
||||
val colorIconAccentGreen = Color(0xFF2DA30D)
|
||||
|
||||
// color.border
|
||||
val colorBorderPrimary = Color(0x0D000000)
|
||||
val colorBorderSecondary = Color(0x1A000000)
|
||||
val colorBorderTertiary = Color(0x33000000)
|
||||
val colorBorderBrand = Color(0xFF0090F9)
|
||||
val colorBorderInversePrimary = Color(0x0D000000)
|
||||
val colorBorderInverseSecondary = Color(0x1A000000)
|
||||
val colorBorderInverseTertiary = Color(0x33000000)
|
||||
val colorBorderStatusSuccess = Color(0xFF2DA30D)
|
||||
val colorBorderStatusError = Color(0xFFF25508)
|
||||
val colorBorderStatusWarning = Color(0xFFE68A03)
|
||||
val colorBorderStatusInfo = Color(0xFF0090F9)
|
||||
val colorBorderAccentBlue = Color(0xFF0090F9)
|
||||
val colorBorderAccentViolet = Color(0xFFA967FD)
|
||||
val colorBorderAccentRed = Color(0xFFFE4142)
|
||||
val colorBorderAccentOrange = Color(0xFFF25508)
|
||||
val colorBorderAccentYellow = Color(0xFFE68A03)
|
||||
val colorBorderAccentGreen = Color(0xFF2DA30D)
|
||||
|
||||
// color.overlay
|
||||
val colorOverlayModal = Color(0x99000000)
|
||||
|
||||
// color.interaction
|
||||
val colorInteractionPress = Color(0x1A000000)
|
||||
val colorInteractionPressStaticLight = Color(0x1A000000)
|
||||
val colorInteractionPressStaticDark = Color(0x1AFFFFFF)
|
||||
val colorInteractionPressInverse = Color(0x1AFFFFFF)
|
||||
|
||||
// color.material
|
||||
val colorMaterialTintGlass = Color(0x00000000)
|
||||
val colorMaterialTintBlur = Color(0x00000000)
|
||||
val colorMaterialTintSolid = Color(0x1AFFFFFF)
|
||||
val colorMaterialFillGlass = Color(0x00000000)
|
||||
val colorMaterialFillBlur = Color(0x99FFFFFF)
|
||||
val colorMaterialFillSolid = Color(0xE6FFFFFF)
|
||||
val colorMaterialLightenGlass = Color(0x80F7F7F7)
|
||||
val colorMaterialLightenBlur = Color(0x00000000)
|
||||
val colorMaterialLightenSolid = Color(0x00000000)
|
||||
val colorMaterialSoftLightGlass = Color(0x33000000)
|
||||
val colorMaterialSoftLightBlur = Color(0x00000000)
|
||||
val colorMaterialSoftLightSolid = Color(0x00000000)
|
||||
val colorMaterialBorderStart = Color(0x26000000)
|
||||
val colorMaterialBorderMid = Color(0x00000000)
|
||||
val colorMaterialBorderEnd = Color(0x1A000000)
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package com.tangem.core.ui.res.generated
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
internal class TangemOpacityTokens {
|
||||
val opacity0 = 0f
|
||||
val opacity5 = 0.05f
|
||||
val opacity10 = 0.1f
|
||||
val opacity15 = 0.15f
|
||||
val opacity20 = 0.2f
|
||||
val opacity25 = 0.25f
|
||||
val opacity30 = 0.3f
|
||||
val opacity40 = 0.4f
|
||||
val opacity50 = 0.5f
|
||||
val opacity60 = 0.6f
|
||||
val opacity70 = 0.7f
|
||||
val opacity80 = 0.8f
|
||||
val opacity90 = 0.9f
|
||||
val opacity100 = 1f
|
||||
val opacityDisabled = 0.4f
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package com.tangem.core.ui.res.generated
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
internal class TangemShadowTokens {
|
||||
val shadowButtonBlur = 40.dp
|
||||
val shadowButtonOffsetX = 0.dp
|
||||
val shadowButtonOffsetY = 8.dp
|
||||
val shadowButtonSpread = 0.dp
|
||||
val shadowButtonColor = Color(0x1A000000)
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
@file:Suppress("all")
|
||||
|
||||
package com.tangem.core.ui.res.generated
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.LineBreak
|
||||
import androidx.compose.ui.text.style.LineHeightStyle
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
@Stable
|
||||
class TangemTypography3 internal constructor(fontFamily: FontFamily) {
|
||||
val display: Display = Display(fontFamily)
|
||||
val heading: Heading = Heading(fontFamily)
|
||||
val body: Body = Body(fontFamily)
|
||||
val subheading: Subheading = Subheading(fontFamily)
|
||||
val caption: Caption = Caption(fontFamily)
|
||||
|
||||
@Stable
|
||||
class Display internal constructor(fontFamily: FontFamily) {
|
||||
val medium: TextStyle = TextStyle(
|
||||
fontFamily = fontFamily,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 44.sp,
|
||||
lineHeight = 52.sp,
|
||||
letterSpacing = (-0.92).sp,
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.None,
|
||||
),
|
||||
lineBreak = LineBreak.Heading,
|
||||
)
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Heading internal constructor(fontFamily: FontFamily) {
|
||||
val medium: TextStyle = TextStyle(
|
||||
fontFamily = fontFamily,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 28.sp,
|
||||
lineHeight = 33.sp,
|
||||
letterSpacing = (-0.37).sp,
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.None,
|
||||
),
|
||||
lineBreak = LineBreak.Heading,
|
||||
)
|
||||
val small: TextStyle = TextStyle(
|
||||
fontFamily = fontFamily,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 20.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = (-0.12).sp,
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.None,
|
||||
),
|
||||
lineBreak = LineBreak.Heading,
|
||||
)
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Body internal constructor(fontFamily: FontFamily) {
|
||||
val medium: TextStyle = TextStyle(
|
||||
fontFamily = fontFamily,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 20.sp,
|
||||
letterSpacing = 0.02.sp,
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.None,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Subheading internal constructor(fontFamily: FontFamily) {
|
||||
val medium: TextStyle = TextStyle(
|
||||
fontFamily = fontFamily,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 17.sp,
|
||||
letterSpacing = 0.07.sp,
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.None,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Stable
|
||||
class Caption internal constructor(fontFamily: FontFamily) {
|
||||
val medium: TextStyle = TextStyle(
|
||||
fontFamily = fontFamily,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.18.sp,
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.None,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
package com.tangem.core.ui.res.generated
|
||||
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.LineBreak
|
||||
import androidx.compose.ui.text.style.LineHeightStyle
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.tangem.core.ui.res.InterFamily
|
||||
|
||||
/**
|
||||
* Auto-generated from design tokens. Do not edit manually.
|
||||
*/
|
||||
internal class TangemTypographyTokens {
|
||||
val fontDisplayMedium = TextStyle(
|
||||
fontFamily = InterFamily,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 44.sp,
|
||||
lineHeight = 52.sp,
|
||||
letterSpacing = (-0.92).sp,
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.None,
|
||||
),
|
||||
lineBreak = LineBreak.Heading,
|
||||
)
|
||||
|
||||
val fontHeadingMedium = TextStyle(
|
||||
fontFamily = InterFamily,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 28.sp,
|
||||
lineHeight = 33.sp,
|
||||
letterSpacing = (-0.37).sp,
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.None,
|
||||
),
|
||||
lineBreak = LineBreak.Heading,
|
||||
)
|
||||
|
||||
val fontHeadingSmall = TextStyle(
|
||||
fontFamily = InterFamily,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 20.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = (-0.12).sp,
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.None,
|
||||
),
|
||||
lineBreak = LineBreak.Heading,
|
||||
)
|
||||
|
||||
val fontBodyMedium = TextStyle(
|
||||
fontFamily = InterFamily,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 20.sp,
|
||||
letterSpacing = 0.02.sp,
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.None,
|
||||
),
|
||||
)
|
||||
|
||||
val fontSubheadingMedium = TextStyle(
|
||||
fontFamily = InterFamily,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 17.sp,
|
||||
letterSpacing = 0.07.sp,
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.None,
|
||||
),
|
||||
)
|
||||
|
||||
val fontCaptionMedium = TextStyle(
|
||||
fontFamily = InterFamily,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.18.sp,
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
trim = LineHeightStyle.Trim.None,
|
||||
),
|
||||
)
|
||||
}
|
||||
21
core/ui/token-gen/README.md
Normal file
21
core/ui/token-gen/README.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# token-gen
|
||||
|
||||
Generates Kotlin (Jetpack Compose) source files from design tokens defined in the `ds-tokens` git submodule.
|
||||
|
||||
## Updating tokens
|
||||
|
||||
1. Update the `ds-tokens` submodule to the latest commit:
|
||||
```bash
|
||||
git submodule update --remote core/ui/ds-tokens
|
||||
```
|
||||
2. Re-run the build:
|
||||
```bash
|
||||
cd core/ui/token-gen && npm run build
|
||||
```
|
||||
3. Commit both the submodule pointer and generated files.
|
||||
|
||||
## How it works
|
||||
|
||||
The script uses [Style Dictionary v5](https://styledictionary.com/) with [@tokens-studio/sd-transforms](https://github.com/tokens-studio/sd-transforms) to read JSON token files from `core/ui/ds-tokens/tokens/` and generate Kotlin files into `core/ui/src/main/java/com/tangem/core/ui/res/generated/`.
|
||||
|
||||
All generated files are written to `com.tangem.core.ui.res.generated` and should not be edited manually.
|
||||
|
|
@ -149,47 +149,368 @@ function groupByPath(tokens, depth = 1) {
|
|||
return groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a tree of nested objects from entries.
|
||||
* Each entry: { path: string[], value: string }.
|
||||
* The last segment is the property name; preceding segments become nested objects.
|
||||
*/
|
||||
function buildPropertyTree(entries) {
|
||||
const root = { props: [], children: new Map() };
|
||||
|
||||
for (const { path, value } of entries) {
|
||||
let node = root;
|
||||
for (let i = 0; i < path.length - 1; i++) {
|
||||
const seg = path[i];
|
||||
if (!node.children.has(seg)) {
|
||||
node.children.set(seg, { props: [], children: new Map() });
|
||||
}
|
||||
node = node.children.get(seg);
|
||||
}
|
||||
const propName = path[path.length - 1];
|
||||
const existingIdx = node.props.findIndex(p => p.name === propName);
|
||||
if (existingIdx >= 0) {
|
||||
console.warn(` ⚠ Duplicate property path: ${path.join('.')} — overwriting`);
|
||||
node.props[existingIdx] = { name: propName, value };
|
||||
} else {
|
||||
node.props.push({ name: propName, value });
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a property tree as Kotlin nested objects.
|
||||
* Returns an array of indented lines.
|
||||
*/
|
||||
function renderTree(node, indent = 1) {
|
||||
const pad = ' '.repeat(indent);
|
||||
const lines = [];
|
||||
|
||||
for (const { name, value } of node.props) {
|
||||
lines.push(`${pad}val ${name} = ${value}`);
|
||||
}
|
||||
|
||||
for (const [name, child] of node.children) {
|
||||
if (lines.length > 0) lines.push('');
|
||||
lines.push(`${pad}object ${name} {`);
|
||||
lines.push(...renderTree(child, indent + 1));
|
||||
lines.push(`${pad}}`);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a @Stable class tree for dimension tokens.
|
||||
* Each node with children becomes a nested @Stable class.
|
||||
* Props carry { default, type } values.
|
||||
*/
|
||||
function renderStableDimenClass(className, node, indent) {
|
||||
const pad = ' '.repeat(indent);
|
||||
const pad1 = ' '.repeat(indent + 1);
|
||||
const lines = [];
|
||||
|
||||
lines.push(`${pad}@Stable`);
|
||||
lines.push(`${pad}class ${className} internal constructor(`);
|
||||
|
||||
for (const { name, value } of node.props) {
|
||||
lines.push(`${pad1}val ${kotlinSafe(name)}: ${value.type} = ${value.default},`);
|
||||
}
|
||||
for (const [childName, childNode] of node.children) {
|
||||
const typeName = capitalize(childName);
|
||||
const propName = kotlinSafe(childName.charAt(0).toLowerCase() + childName.slice(1));
|
||||
lines.push(`${pad1}val ${propName}: ${typeName} = ${typeName}(),`);
|
||||
}
|
||||
|
||||
if (node.children.size === 0) {
|
||||
lines.push(`${pad})`);
|
||||
} else {
|
||||
lines.push(`${pad}) {`);
|
||||
|
||||
let first = true;
|
||||
for (const [childName, childNode] of node.children) {
|
||||
if (!first) lines.push('');
|
||||
first = false;
|
||||
lines.push(...renderStableDimenClass(capitalize(childName), childNode, indent + 1));
|
||||
}
|
||||
|
||||
lines.push(`${pad}}`);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Capitalize the first letter of a string.
|
||||
*/
|
||||
function capitalize(str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a kebab-case segment to PascalCase (for object names).
|
||||
*/
|
||||
function toPascalCase(seg) {
|
||||
return seg
|
||||
.split('-')
|
||||
.map(part => capitalize(part))
|
||||
.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a name in backticks if it starts with a digit or is a Kotlin hard keyword.
|
||||
*/
|
||||
const KOTLIN_HARD_KEYWORDS = new Set([
|
||||
'as', 'break', 'class', 'continue', 'do', 'else', 'false', 'for', 'fun',
|
||||
'if', 'in', 'interface', 'is', 'null', 'object', 'package', 'return',
|
||||
'super', 'this', 'throw', 'true', 'try', 'typealias', 'typeof', 'val',
|
||||
'var', 'when', 'while',
|
||||
]);
|
||||
|
||||
function kotlinSafe(name) {
|
||||
if (/^\d/.test(name) || KOTLIN_HARD_KEYWORDS.has(name)) return `\`${name}\``;
|
||||
return name;
|
||||
}
|
||||
|
||||
// ── TangemColors3 helpers ─────────────────────────────────────────────────────
|
||||
|
||||
/** Shared structure tree for TangemColors3, computed from light theme codeSyntax. */
|
||||
let colors3StructureTree = null;
|
||||
|
||||
/** Extract codeSyntax.Android path, stripping TangemTheme.colors3. prefix. */
|
||||
function getAndroidCodeSyntax(token) {
|
||||
const ext = token.$extensions?.['com.figma.codeSyntax'];
|
||||
if (!ext?.Android) return null;
|
||||
const prefix = 'TangemTheme.colors3.';
|
||||
const android = ext.Android;
|
||||
return android.startsWith(prefix) ? android.slice(prefix.length) : null;
|
||||
}
|
||||
|
||||
/** Get the token's property path for the class tree from codeSyntax, or fallback to JSON path. */
|
||||
function colorTokenClassPath(token) {
|
||||
const cs = getAndroidCodeSyntax(token);
|
||||
if (cs) return cs.split('.');
|
||||
// Fallback for material tokens (no codeSyntax): use JSON path minus 'color' prefix
|
||||
const pathSegs = token.path.slice(1); // remove 'color'
|
||||
return pathSegs.map(seg => seg.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a simple palette reference from a token's original (unresolved) value.
|
||||
* Returns the reference string like "palette.neutral.95" or null for complex values.
|
||||
*/
|
||||
function extractPaletteRef(token) {
|
||||
const original = token.original?.$value;
|
||||
if (typeof original !== 'string') return null;
|
||||
const match = original.match(/^\{(palette\.[^}]+)\}$/);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a palette reference path to Kotlin code referencing TangemColorPalette.
|
||||
* e.g., "palette.neutral.95" → "TangemColorPalette.Neutral.`95`"
|
||||
* e.g., "palette.opaque.base-black.60" → "TangemColorPalette.Opaque.BaseBlack.`60`"
|
||||
*/
|
||||
function paletteRefToKotlin(refPath) {
|
||||
const parts = refPath.split('.').slice(1); // drop "palette"
|
||||
const objParts = parts.slice(0, -1).map(seg => toPascalCase(seg));
|
||||
const leaf = parts[parts.length - 1].replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
||||
return `TangemColorPalette.${objParts.join('.')}.${kotlinSafe(leaf)}`;
|
||||
}
|
||||
|
||||
/** Get Kotlin value for a color token: palette reference if simple, else resolved Color literal. */
|
||||
function paletteRefOrColor(token) {
|
||||
const ref = extractPaletteRef(token);
|
||||
if (ref) return paletteRefToKotlin(ref);
|
||||
return toComposeColor(token.$value, token.path.join('.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a class structure tree from color tokens using codeSyntax paths.
|
||||
* Each node: { props: [{name, jsonPath}], children: Map<string, node> }
|
||||
*/
|
||||
function buildClassStructureTree(tokens) {
|
||||
const root = { props: [], children: new Map() };
|
||||
|
||||
for (const token of tokens) {
|
||||
const classPath = colorTokenClassPath(token);
|
||||
const jsonPath = token.path.join('.');
|
||||
|
||||
let node = root;
|
||||
for (let i = 0; i < classPath.length - 1; i++) {
|
||||
const seg = classPath[i];
|
||||
if (!node.children.has(seg)) {
|
||||
node.children.set(seg, { props: [], children: new Map() });
|
||||
}
|
||||
node = node.children.get(seg);
|
||||
}
|
||||
|
||||
const propName = classPath[classPath.length - 1];
|
||||
const existingIdx = node.props.findIndex(p => p.name === propName);
|
||||
if (existingIdx >= 0) {
|
||||
console.warn(` ⚠ Duplicate codeSyntax path: ${classPath.join('.')} (${jsonPath}) — overwriting`);
|
||||
node.props[existingIdx] = { name: propName, jsonPath };
|
||||
} else {
|
||||
node.props.push({ name: propName, jsonPath });
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve conflicts where a name appears as both a leaf property and a child class.
|
||||
* Resolution: move the leaf into the child as "default".
|
||||
*/
|
||||
function resolveClassTreeConflicts(node) {
|
||||
const propsToRemove = [];
|
||||
|
||||
for (const [childName, childNode] of node.children) {
|
||||
const conflictIdx = node.props.findIndex(p => p.name === childName);
|
||||
if (conflictIdx >= 0) {
|
||||
const prop = node.props[conflictIdx];
|
||||
console.log(` ℹ Conflict resolved: "${childName}" is both property and class → moved to "${childName}.default"`);
|
||||
childNode.props.unshift({ name: 'default', jsonPath: prop.jsonPath });
|
||||
propsToRemove.push(conflictIdx);
|
||||
}
|
||||
}
|
||||
|
||||
for (const idx of propsToRemove.sort((a, b) => b - a)) {
|
||||
node.props.splice(idx, 1);
|
||||
}
|
||||
|
||||
for (const child of node.children.values()) {
|
||||
resolveClassTreeConflicts(child);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a @Stable class with mutableStateOf pattern for Compose theme colors.
|
||||
* Returns array of Kotlin source lines.
|
||||
*/
|
||||
function renderStableClass(className, node, indent = 0) {
|
||||
const pad = ' '.repeat(indent);
|
||||
const pad1 = ' '.repeat(indent + 1);
|
||||
const pad2 = ' '.repeat(indent + 2);
|
||||
const lines = [];
|
||||
|
||||
lines.push(`${pad}@Stable`);
|
||||
lines.push(`${pad}class ${className} internal constructor(`);
|
||||
|
||||
for (const { name } of node.props) {
|
||||
lines.push(`${pad1}${kotlinSafe(name)}: Color,`);
|
||||
}
|
||||
for (const [childName] of node.children) {
|
||||
lines.push(`${pad1}val ${childName}: ${capitalize(childName)},`);
|
||||
}
|
||||
|
||||
lines.push(`${pad}) {`);
|
||||
|
||||
// mutableStateOf delegates for leaf Color props
|
||||
if (node.props.length > 0) {
|
||||
for (const { name } of node.props) {
|
||||
const safe = kotlinSafe(name);
|
||||
lines.push(`${pad1}var ${safe} by mutableStateOf(${safe})`);
|
||||
lines.push(`${pad2}private set`);
|
||||
}
|
||||
}
|
||||
|
||||
// Nested child classes
|
||||
for (const [childName, childNode] of node.children) {
|
||||
lines.push('');
|
||||
lines.push(...renderStableClass(capitalize(childName), childNode, indent + 1));
|
||||
}
|
||||
|
||||
// update() function
|
||||
lines.push('');
|
||||
lines.push(`${pad1}fun update(other: ${className}) {`);
|
||||
for (const { name } of node.props) {
|
||||
const safe = kotlinSafe(name);
|
||||
lines.push(`${pad2}${safe} = other.${safe}`);
|
||||
}
|
||||
for (const [childName] of node.children) {
|
||||
lines.push(`${pad2}${childName}.update(other.${childName})`);
|
||||
}
|
||||
lines.push(`${pad1}}`);
|
||||
|
||||
lines.push(`${pad}}`);
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the content lines of a factory constructor call (param assignments + child constructors).
|
||||
*/
|
||||
function renderFactoryContent(classPath, node, valueMap, indent) {
|
||||
const pad = ' '.repeat(indent);
|
||||
const lines = [];
|
||||
|
||||
for (const { name, jsonPath } of node.props) {
|
||||
const value = valueMap.get(jsonPath);
|
||||
if (!value) console.warn(` ⚠ No value for jsonPath "${jsonPath}" (property: ${name})`);
|
||||
lines.push(`${pad}${kotlinSafe(name)} = ${value || 'Color.Unspecified'},`);
|
||||
}
|
||||
|
||||
for (const [childName, childNode] of node.children) {
|
||||
const childClassPath = `${classPath}.${capitalize(childName)}`;
|
||||
lines.push(`${pad}${childName} = ${childClassPath}(`);
|
||||
lines.push(...renderFactoryContent(childClassPath, childNode, valueMap, indent + 1));
|
||||
lines.push(`${pad}),`);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
const FILE_SUPPRESS = '@file:Suppress("all")';
|
||||
|
||||
// ── Custom formats ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Kotlin format for color tokens.
|
||||
* Generates: class TangemLightColorTokens / TangemDarkColorTokens
|
||||
* Kotlin format for palette tokens.
|
||||
* Generates nested objects: object Base { val black = ... }, object Neutral { val `5` = ... }, etc.
|
||||
*/
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'kotlin/compose-colors',
|
||||
format: ({ dictionary, options }) => {
|
||||
const themeName = options.themeName; // "Light" or "Dark"
|
||||
const objectName = `Tangem${themeName}ColorTokens`;
|
||||
|
||||
const colorTokens = dictionary.allTokens.filter(
|
||||
t => t.$type === 'color' && !isSourceOnlyToken(t),
|
||||
name: 'kotlin/compose-palette',
|
||||
format: ({ dictionary }) => {
|
||||
const paletteTokens = dictionary.allTokens.filter(
|
||||
t => t.$type === 'color' && t.path[0] === 'palette',
|
||||
);
|
||||
|
||||
// Group by top-level category (color.text, color.bg, color.icon, etc.)
|
||||
const groups = groupByPath(colorTokens, 2);
|
||||
const sections = [];
|
||||
|
||||
for (const [groupKey, tokens] of Object.entries(groups)) {
|
||||
const comment = ` // ${groupKey}`;
|
||||
const props = tokens.map(token => {
|
||||
const propName = toCamelCase(token.path);
|
||||
const value = toComposeColor(token.$value, token.path.join('.'));
|
||||
return ` val ${propName} = ${value}`;
|
||||
});
|
||||
sections.push([comment, ...props].join('\n'));
|
||||
const entries = paletteTokens.map(token => {
|
||||
// palette.base.black → ["Base", "black"]
|
||||
// palette.neutral.5 → ["Neutral", "`5`"]
|
||||
// palette.opaque.base-black.5 → ["Opaque", "BaseBlack", "`5`"]
|
||||
const segments = token.path.slice(1); // drop "palette"
|
||||
const path = segments.map((seg, i) => {
|
||||
if (i < segments.length - 1) {
|
||||
// intermediate segments → PascalCase object names
|
||||
return toPascalCase(seg);
|
||||
}
|
||||
// leaf segment → property name, backtick-wrap if starts with digit
|
||||
const camel = seg.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
||||
return kotlinSafe(camel);
|
||||
});
|
||||
|
||||
const value = toComposeColor(token.$value, token.path.join('.'));
|
||||
return { path, value };
|
||||
});
|
||||
|
||||
const tree = buildPropertyTree(entries);
|
||||
const body = renderTree(tree);
|
||||
|
||||
return [
|
||||
FILE_SUPPRESS,
|
||||
'',
|
||||
`package ${PACKAGE}`,
|
||||
'',
|
||||
'import androidx.compose.ui.graphics.Color',
|
||||
'',
|
||||
'/**',
|
||||
` * Auto-generated from design tokens. Do not edit manually.`,
|
||||
` * Theme: ${themeName}`,
|
||||
' * Auto-generated from design tokens. Do not edit manually.',
|
||||
' */',
|
||||
`internal class ${objectName} {`,
|
||||
sections.join('\n\n'),
|
||||
'internal object TangemColorPalette {',
|
||||
body.join('\n'),
|
||||
'}',
|
||||
'',
|
||||
].join('\n');
|
||||
|
|
@ -197,100 +518,98 @@ StyleDictionary.registerFormat({
|
|||
});
|
||||
|
||||
/**
|
||||
* Kotlin format for dimension tokens (spacing, size, border-radius, border-width).
|
||||
* Kotlin format for TangemDimens3 — structured dimension tokens as @Immutable data class.
|
||||
* Generates nested @Immutable data classes from codeSyntax.Android paths (prefix: TangemTheme.dimens3.).
|
||||
* Includes spacing, size, borderRadius, borderWidth, blur, and semantic opacity tokens.
|
||||
*/
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'kotlin/compose-dimensions',
|
||||
name: 'kotlin/compose-dimens3',
|
||||
format: ({ dictionary }) => {
|
||||
const dimTokens = dictionary.allTokens.filter(t => {
|
||||
// Exclude font tokens — letter-spacing values are already in typography tokens as sp
|
||||
if (t.path[0] === 'font') return false;
|
||||
return (
|
||||
(t.$type === 'dimension' || t.$type === 'borderRadius' || t.$type === 'borderWidth') &&
|
||||
!isSourceOnlyToken(t)
|
||||
);
|
||||
});
|
||||
const prefix = 'TangemTheme.dimens3.';
|
||||
|
||||
const groups = groupByPath(dimTokens, 1);
|
||||
const sections = [];
|
||||
const entries = [];
|
||||
for (const token of dictionary.allTokens) {
|
||||
const ext = token.$extensions?.['com.figma.codeSyntax'];
|
||||
if (!ext?.Android?.startsWith(prefix)) continue;
|
||||
|
||||
const codePath = ext.Android.slice(prefix.length);
|
||||
const segPath = codePath.split('.');
|
||||
|
||||
for (const [groupKey, tokens] of Object.entries(groups)) {
|
||||
const comment = ` // ${groupKey}`;
|
||||
const props = tokens.map(token => {
|
||||
const propName = toCamelCase(token.path);
|
||||
// Resolved value is in px (number), convert to dp
|
||||
const raw = parseFloat(token.$value);
|
||||
if (isNaN(raw)) throw new Error(`Non-numeric dimension value for ${token.path.join('.')}: "${token.$value}"`);
|
||||
const dpVal = `${raw}.dp`;
|
||||
return ` val ${propName} = ${dpVal}`;
|
||||
});
|
||||
sections.push([comment, ...props].join('\n'));
|
||||
const tp = token.path.join('.');
|
||||
if (isNaN(raw)) throw new Error(`Non-numeric value for ${tp}: "${token.$value}"`);
|
||||
|
||||
// Opacity tokens → Float, all others → Dp
|
||||
const isOpacity = token.$type === 'opacity';
|
||||
const value = isOpacity ? `${raw}f` : `${raw}.dp`;
|
||||
const type = isOpacity ? 'Float' : 'Dp';
|
||||
|
||||
entries.push({ path: segPath, value, type });
|
||||
}
|
||||
|
||||
const tree = buildPropertyTree(entries.map(e => ({
|
||||
path: e.path,
|
||||
value: { default: e.value, type: e.type },
|
||||
})));
|
||||
|
||||
const classLines = renderStableDimenClass('TangemDimens3', tree, 0);
|
||||
|
||||
return [
|
||||
FILE_SUPPRESS,
|
||||
'',
|
||||
`package ${PACKAGE}`,
|
||||
'',
|
||||
'import androidx.compose.runtime.Stable',
|
||||
'import androidx.compose.ui.unit.Dp',
|
||||
'import androidx.compose.ui.unit.dp',
|
||||
'',
|
||||
'/**',
|
||||
' * Auto-generated from design tokens. Do not edit manually.',
|
||||
' */',
|
||||
'internal class TangemDimensionTokens {',
|
||||
sections.join('\n\n'),
|
||||
'}',
|
||||
...classLines,
|
||||
'',
|
||||
].join('\n');
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Kotlin format for opacity tokens.
|
||||
* Kotlin format for TangemTypography3 — @Stable class with nested categories.
|
||||
* Generates a class taking FontFamily, with nested classes for each typography category
|
||||
* (display, heading, body, subheading, caption).
|
||||
*/
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'kotlin/compose-opacity',
|
||||
format: ({ dictionary }) => {
|
||||
const opacityTokens = dictionary.allTokens.filter(
|
||||
t => t.$type === 'opacity' && !isSourceOnlyToken(t),
|
||||
);
|
||||
|
||||
const props = opacityTokens.map(token => {
|
||||
const propName = toCamelCase(token.path);
|
||||
const raw = parseFloat(token.$value);
|
||||
if (isNaN(raw)) throw new Error(`Non-numeric opacity value for ${token.path.join('.')}: "${token.$value}"`);
|
||||
const floatVal = `${raw}f`;
|
||||
return ` val ${propName} = ${floatVal}`;
|
||||
});
|
||||
|
||||
return [
|
||||
`package ${PACKAGE}`,
|
||||
'',
|
||||
'/**',
|
||||
' * Auto-generated from design tokens. Do not edit manually.',
|
||||
' */',
|
||||
'internal class TangemOpacityTokens {',
|
||||
...props,
|
||||
'}',
|
||||
'',
|
||||
].join('\n');
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Kotlin format for typography tokens.
|
||||
*/
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'kotlin/compose-typography',
|
||||
name: 'kotlin/compose-typography3',
|
||||
format: ({ dictionary }) => {
|
||||
const typoTokens = dictionary.allTokens.filter(
|
||||
t => t.$type === 'typography' && !isSourceOnlyToken(t),
|
||||
);
|
||||
|
||||
const props = typoTokens.map(token => {
|
||||
const propName = toCamelCase(token.path);
|
||||
const v = token.$value;
|
||||
// Group by category (path[1]: display, heading, body, subheading, caption)
|
||||
const categories = new Map();
|
||||
for (const token of typoTokens) {
|
||||
const category = token.path[1];
|
||||
if (!categories.has(category)) categories.set(category, []);
|
||||
categories.get(category).push(token);
|
||||
}
|
||||
|
||||
// v is an object: { fontFamily, fontWeight, fontSize, lineHeight, letterSpacing, ... }
|
||||
// Build nested class lines
|
||||
const outerProps = [];
|
||||
const innerClasses = [];
|
||||
|
||||
for (const [category, tokens] of categories) {
|
||||
const className = capitalize(category);
|
||||
const propName = category;
|
||||
const isHeading = category === 'display' || category === 'heading';
|
||||
|
||||
outerProps.push(` val ${propName}: ${className} = ${className}(fontFamily)`);
|
||||
|
||||
const classLines = [` @Stable`, ` class ${className} internal constructor(fontFamily: FontFamily) {`];
|
||||
|
||||
for (const token of tokens) {
|
||||
const size = token.path[2]; // medium, small, etc.
|
||||
const v = token.$value;
|
||||
const tp = token.path.join('.');
|
||||
|
||||
if (!v.fontWeight) throw new Error(`Missing fontWeight for ${tp}`);
|
||||
const fontWeight = mapFontWeight(v.fontWeight);
|
||||
const fontSize = parseFloat(v.fontSize);
|
||||
|
|
@ -300,45 +619,49 @@ StyleDictionary.registerFormat({
|
|||
const letterSpacing = parseFloat(v.letterSpacing);
|
||||
if (isNaN(letterSpacing)) throw new Error(`Non-numeric letterSpacing for ${tp}: "${v.letterSpacing}"`);
|
||||
|
||||
// display and heading categories get LineBreak.Heading (matches TangemTypography2)
|
||||
const category = token.path[1]; // display, heading, body, subheading, caption
|
||||
const isHeading = category === 'display' || category === 'heading';
|
||||
const spacingLiteral = letterSpacing < 0 ? `(${letterSpacing})` : `${letterSpacing}`;
|
||||
|
||||
const lines = [
|
||||
` val ${propName} = TextStyle(`,
|
||||
` fontFamily = InterFamily,`,
|
||||
` fontWeight = ${fontWeight},`,
|
||||
` fontSize = ${fontSize}.sp,`,
|
||||
` lineHeight = ${lineHeight}.sp,`,
|
||||
` letterSpacing = ${letterSpacing < 0 ? `(${letterSpacing})` : letterSpacing}.sp,`,
|
||||
` lineHeightStyle = LineHeightStyle(`,
|
||||
` alignment = LineHeightStyle.Alignment.Center,`,
|
||||
` trim = LineHeightStyle.Trim.None,`,
|
||||
` ),`,
|
||||
];
|
||||
classLines.push(` val ${size}: TextStyle = TextStyle(`);
|
||||
classLines.push(` fontFamily = fontFamily,`);
|
||||
classLines.push(` fontWeight = ${fontWeight},`);
|
||||
classLines.push(` fontSize = ${fontSize}.sp,`);
|
||||
classLines.push(` lineHeight = ${lineHeight}.sp,`);
|
||||
classLines.push(` letterSpacing = ${spacingLiteral}.sp,`);
|
||||
classLines.push(` lineHeightStyle = LineHeightStyle(`);
|
||||
classLines.push(` alignment = LineHeightStyle.Alignment.Center,`);
|
||||
classLines.push(` trim = LineHeightStyle.Trim.None,`);
|
||||
classLines.push(` ),`);
|
||||
if (isHeading) {
|
||||
lines.push(` lineBreak = LineBreak.Heading,`);
|
||||
classLines.push(` lineBreak = LineBreak.Heading,`);
|
||||
}
|
||||
classLines.push(` )`);
|
||||
}
|
||||
lines.push(` )`);
|
||||
|
||||
return lines.join('\n');
|
||||
});
|
||||
classLines.push(` }`);
|
||||
innerClasses.push(classLines.join('\n'));
|
||||
}
|
||||
|
||||
return [
|
||||
FILE_SUPPRESS,
|
||||
'',
|
||||
`package ${PACKAGE}`,
|
||||
'',
|
||||
'import androidx.compose.runtime.Stable',
|
||||
'import androidx.compose.ui.text.TextStyle',
|
||||
'import androidx.compose.ui.text.font.FontFamily',
|
||||
'import androidx.compose.ui.text.font.FontWeight',
|
||||
'import androidx.compose.ui.text.style.LineBreak',
|
||||
'import androidx.compose.ui.text.style.LineHeightStyle',
|
||||
'import androidx.compose.ui.unit.sp',
|
||||
'import com.tangem.core.ui.res.InterFamily',
|
||||
'',
|
||||
'/**',
|
||||
' * Auto-generated from design tokens. Do not edit manually.',
|
||||
' */',
|
||||
'internal class TangemTypographyTokens {',
|
||||
props.join('\n\n'),
|
||||
'@Stable',
|
||||
'class TangemTypography3 internal constructor(fontFamily: FontFamily) {',
|
||||
outerProps.join('\n'),
|
||||
'',
|
||||
innerClasses.join('\n\n'),
|
||||
'}',
|
||||
'',
|
||||
].join('\n');
|
||||
|
|
@ -361,54 +684,88 @@ function mapFontWeight(value) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Kotlin format for shadow tokens.
|
||||
* Shadow tokens are composite (type: shadow) with object $value containing
|
||||
* blur, spread, color, offsetX, offsetY, type.
|
||||
* Kotlin format for TangemColors3 class definition.
|
||||
* Generates the @Stable class hierarchy with mutableStateOf + update() pattern.
|
||||
* Structure is derived from light theme codeSyntax.Android fields.
|
||||
*/
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'kotlin/compose-shadows',
|
||||
name: 'kotlin/compose-colors3-class',
|
||||
format: ({ dictionary }) => {
|
||||
const shadowTokens = dictionary.allTokens.filter(
|
||||
t => (t.$type === 'shadow' || t.$type === 'boxShadow') && !isSourceOnlyToken(t),
|
||||
const colorTokens = dictionary.allTokens.filter(
|
||||
t => t.$type === 'color' && !isSourceOnlyToken(t),
|
||||
);
|
||||
|
||||
const entries = shadowTokens.map(token => {
|
||||
const propName = toCamelCase(token.path);
|
||||
const v = token.$value;
|
||||
const sp = token.path.join('.');
|
||||
if (!v) throw new Error(`Missing shadow value for ${sp}`);
|
||||
const blur = parseFloat(v.blur);
|
||||
if (isNaN(blur)) throw new Error(`Non-numeric blur for ${sp}: "${v.blur}"`);
|
||||
const spread = parseFloat(v.spread);
|
||||
if (isNaN(spread)) throw new Error(`Non-numeric spread for ${sp}: "${v.spread}"`);
|
||||
const offsetX = parseFloat(v.offsetX);
|
||||
if (isNaN(offsetX)) throw new Error(`Non-numeric offsetX for ${sp}: "${v.offsetX}"`);
|
||||
const offsetY = parseFloat(v.offsetY);
|
||||
if (isNaN(offsetY)) throw new Error(`Non-numeric offsetY for ${sp}: "${v.offsetY}"`);
|
||||
if (!v.color) throw new Error(`Missing color for ${sp}`);
|
||||
const colorVal = toComposeColor(v.color, sp + '.color');
|
||||
|
||||
return [
|
||||
` val ${propName}Blur = ${blur}.dp`,
|
||||
` val ${propName}OffsetX = ${offsetX}.dp`,
|
||||
` val ${propName}OffsetY = ${offsetY}.dp`,
|
||||
` val ${propName}Spread = ${spread}.dp`,
|
||||
` val ${propName}Color = ${colorVal}`,
|
||||
].join('\n');
|
||||
});
|
||||
colors3StructureTree = buildClassStructureTree(colorTokens);
|
||||
resolveClassTreeConflicts(colors3StructureTree);
|
||||
|
||||
const classLines = renderStableClass('TangemColors3', colors3StructureTree, 0);
|
||||
|
||||
return [
|
||||
FILE_SUPPRESS,
|
||||
'',
|
||||
`package ${PACKAGE}`,
|
||||
'',
|
||||
'import androidx.compose.runtime.Stable',
|
||||
'import androidx.compose.runtime.getValue',
|
||||
'import androidx.compose.runtime.mutableStateOf',
|
||||
'import androidx.compose.runtime.setValue',
|
||||
'import androidx.compose.ui.graphics.Color',
|
||||
'import androidx.compose.ui.unit.dp',
|
||||
'',
|
||||
'/**',
|
||||
' * Auto-generated from design tokens. Do not edit manually.',
|
||||
' */',
|
||||
'internal class TangemShadowTokens {',
|
||||
entries.join('\n\n'),
|
||||
'}',
|
||||
...classLines,
|
||||
'',
|
||||
].join('\n');
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Kotlin format for TangemColors3 light/dark factory functions.
|
||||
* Generates lightColors3() / darkColors3() functions referencing TangemColorPalette.
|
||||
*/
|
||||
StyleDictionary.registerFormat({
|
||||
name: 'kotlin/compose-colors3-factory',
|
||||
format: ({ dictionary, options }) => {
|
||||
const themeName = options.themeName;
|
||||
const funcName = `${themeName.toLowerCase()}Colors3`;
|
||||
|
||||
// Ensure tree is built (should already be set by class format in Light build)
|
||||
if (!colors3StructureTree) {
|
||||
const colorTokens = dictionary.allTokens.filter(
|
||||
t => t.$type === 'color' && !isSourceOnlyToken(t),
|
||||
);
|
||||
colors3StructureTree = buildClassStructureTree(colorTokens);
|
||||
resolveClassTreeConflicts(colors3StructureTree);
|
||||
}
|
||||
|
||||
// Build value map: jsonPath → Kotlin palette reference or Color literal
|
||||
const colorTokens = dictionary.allTokens.filter(
|
||||
t => t.$type === 'color' && !isSourceOnlyToken(t),
|
||||
);
|
||||
const valueMap = new Map();
|
||||
for (const token of colorTokens) {
|
||||
const jsonPath = token.path.join('.');
|
||||
valueMap.set(jsonPath, paletteRefOrColor(token));
|
||||
}
|
||||
|
||||
const bodyLines = renderFactoryContent('TangemColors3', colors3StructureTree, valueMap, 2);
|
||||
|
||||
return [
|
||||
FILE_SUPPRESS,
|
||||
'',
|
||||
`package ${PACKAGE}`,
|
||||
'',
|
||||
'import androidx.compose.ui.graphics.Color',
|
||||
'',
|
||||
'/**',
|
||||
` * Auto-generated from design tokens. Do not edit manually.`,
|
||||
` * Theme: ${themeName}`,
|
||||
' */',
|
||||
`internal fun ${funcName}() =`,
|
||||
' TangemColors3(',
|
||||
...bodyLines,
|
||||
' )',
|
||||
'',
|
||||
].join('\n');
|
||||
},
|
||||
|
|
@ -425,6 +782,27 @@ const composePlatformTransforms = [
|
|||
for (const [themeName, { sets }] of Object.entries(themeBuilds)) {
|
||||
console.log(`\nBuilding ${themeName} color tokens...`);
|
||||
|
||||
const colorFilter = token => token.$type === 'color' && !isSourceOnlyToken(token);
|
||||
|
||||
const files = [];
|
||||
|
||||
// Only light build generates the class definition (canonical codeSyntax structure)
|
||||
if (themeName === 'Light') {
|
||||
files.push({
|
||||
destination: 'TangemColors3.kt',
|
||||
format: 'kotlin/compose-colors3-class',
|
||||
filter: colorFilter,
|
||||
});
|
||||
}
|
||||
|
||||
// Both themes generate factory functions
|
||||
files.push({
|
||||
destination: `TangemColors3${themeName}.kt`,
|
||||
format: 'kotlin/compose-colors3-factory',
|
||||
options: { themeName },
|
||||
filter: colorFilter,
|
||||
});
|
||||
|
||||
const sd = new StyleDictionary({
|
||||
source: sets.map(s => path.join(tokensDir, `${s}.json`)),
|
||||
preprocessors: ['tokens-studio'],
|
||||
|
|
@ -434,24 +812,44 @@ for (const [themeName, { sets }] of Object.entries(themeBuilds)) {
|
|||
compose: {
|
||||
transforms: composePlatformTransforms,
|
||||
buildPath: outputDir + '/',
|
||||
files: [
|
||||
{
|
||||
destination: `Tangem${themeName}ColorTokens.kt`,
|
||||
format: 'kotlin/compose-colors',
|
||||
options: { themeName },
|
||||
filter: token => token.$type === 'color' && !isSourceOnlyToken(token),
|
||||
},
|
||||
],
|
||||
files,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await sd.buildAllPlatforms();
|
||||
console.log(` ✓ Tangem${themeName}ColorTokens.kt`);
|
||||
if (themeName === 'Light') console.log(' ✓ TangemColors3.kt');
|
||||
console.log(` ✓ TangemColors3${themeName}.kt`);
|
||||
}
|
||||
|
||||
// Build theme-independent tokens (dimensions, opacity, typography, shadows)
|
||||
console.log('\nBuilding dimension, opacity, typography, and shadow tokens...');
|
||||
// Build palette tokens
|
||||
console.log('\nBuilding palette tokens...');
|
||||
|
||||
const paletteSd = new StyleDictionary({
|
||||
source: [...coreSets, 'semantic/size/opacity'].map(s => path.join(tokensDir, `${s}.json`)),
|
||||
preprocessors: ['tokens-studio'],
|
||||
usesDtcg: true,
|
||||
log: { warnings: 'disabled', errors: { brokenReferences: 'console' } },
|
||||
platforms: {
|
||||
compose: {
|
||||
transforms: composePlatformTransforms,
|
||||
buildPath: outputDir + '/',
|
||||
files: [
|
||||
{
|
||||
destination: 'TangemColorPalette.kt',
|
||||
format: 'kotlin/compose-palette',
|
||||
filter: token => token.$type === 'color' && token.path[0] === 'palette',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await paletteSd.buildAllPlatforms();
|
||||
console.log(' ✓ TangemColorPalette.kt');
|
||||
|
||||
// Build theme-independent tokens (dimensions, typography)
|
||||
console.log('\nBuilding dimension and typography tokens...');
|
||||
|
||||
const sd = new StyleDictionary({
|
||||
source: sharedBuildSets.map(s => path.join(tokensDir, `${s}.json`)),
|
||||
|
|
@ -464,42 +862,22 @@ const sd = new StyleDictionary({
|
|||
buildPath: outputDir + '/',
|
||||
files: [
|
||||
{
|
||||
destination: 'TangemDimensionTokens.kt',
|
||||
format: 'kotlin/compose-dimensions',
|
||||
filter: token => {
|
||||
const t = token.$type;
|
||||
return (
|
||||
token.path[0] !== 'font' &&
|
||||
(t === 'dimension' || t === 'borderRadius' || t === 'borderWidth') &&
|
||||
!isSourceOnlyToken(token)
|
||||
);
|
||||
},
|
||||
destination: 'TangemDimens3.kt',
|
||||
format: 'kotlin/compose-dimens3',
|
||||
},
|
||||
{
|
||||
destination: 'TangemOpacityTokens.kt',
|
||||
format: 'kotlin/compose-opacity',
|
||||
filter: token => token.$type === 'opacity' && !isSourceOnlyToken(token),
|
||||
},
|
||||
{
|
||||
destination: 'TangemTypographyTokens.kt',
|
||||
format: 'kotlin/compose-typography',
|
||||
destination: 'TangemTypography3.kt',
|
||||
format: 'kotlin/compose-typography3',
|
||||
filter: token => token.$type === 'typography' && !isSourceOnlyToken(token),
|
||||
},
|
||||
{
|
||||
destination: 'TangemShadowTokens.kt',
|
||||
format: 'kotlin/compose-shadows',
|
||||
filter: token => (token.$type === 'shadow' || token.$type === 'boxShadow') && !isSourceOnlyToken(token),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await sd.buildAllPlatforms();
|
||||
console.log(' ✓ TangemDimensionTokens.kt');
|
||||
console.log(' ✓ TangemOpacityTokens.kt');
|
||||
console.log(' ✓ TangemTypographyTokens.kt');
|
||||
console.log(' ✓ TangemShadowTokens.kt');
|
||||
console.log(' ✓ TangemDimens3.kt');
|
||||
console.log(' ✓ TangemTypography3.kt');
|
||||
|
||||
// ── Write source hash ─────────────────────────────────────────────────────────
|
||||
// Hash all token JSON files so Gradle can verify generated code matches ds-tokens.
|
||||
|
|
@ -513,7 +891,12 @@ function computeTokensHash() {
|
|||
}
|
||||
}
|
||||
walk(tokensDir);
|
||||
files.sort(); // deterministic order
|
||||
// Sort by relative path with forward slashes to match Gradle's invariantSeparatorsPath sorting
|
||||
files.sort((a, b) => {
|
||||
const ra = path.relative(tokensDir, a).split(path.sep).join('/');
|
||||
const rb = path.relative(tokensDir, b).split(path.sep).join('/');
|
||||
return ra.localeCompare(rb);
|
||||
});
|
||||
|
||||
const hash = crypto.createHash('sha256');
|
||||
for (const file of files) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue