Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-08 19:11:28 +03:00
parent 427715888d
commit db9ec70213
15 changed files with 115 additions and 328 deletions

View file

@ -87,8 +87,8 @@ fun TangemBadge(
.heightIn(min = sizeTokens.minHeight),
onClick = onClick,
color = colorTokens.backgroundColor,
border = colorTokens.borderColor?.let { BorderStroke(TangemTheme.dimens3.borderWidth.sm, it) },
shape = RoundedCornerShape(TangemTheme.dimens3.borderRadius.full),
border = colorTokens.borderColor?.let { BorderStroke(1.dp, it) },
shape = RoundedCornerShape(999.dp),
) {
BadgeContent(
iconStart = iconStart,
@ -206,30 +206,29 @@ private data class BadgeSizeTokens(
@Composable
@ReadOnlyComposable
private fun TangemBadge.Size.tokens(): BadgeSizeTokens {
val dimens = TangemTheme.dimens3
val typography = TangemTheme.typography3
return when (this) {
TangemBadge.Size.X9 -> BadgeSizeTokens(
minHeight = dimens.size.s450,
containerHorizontalPadding = dimens.spacing.s100,
containerVerticalPadding = dimens.spacing.s100,
labelPadding = dimens.spacing.s050,
minHeight = 36.dp,
containerHorizontalPadding = 8.dp,
containerVerticalPadding = 8.dp,
labelPadding = 4.dp,
iconSize = 20.dp,
textStyle = typography.subheading.medium,
)
TangemBadge.Size.X6 -> BadgeSizeTokens(
minHeight = dimens.size.s300,
containerHorizontalPadding = dimens.spacing.s050,
containerVerticalPadding = dimens.spacing.s050,
labelPadding = dimens.spacing.s050,
minHeight = 24.dp,
containerHorizontalPadding = 4.dp,
containerVerticalPadding = 4.dp,
labelPadding = 4.dp,
iconSize = 16.dp,
textStyle = typography.caption.medium,
)
TangemBadge.Size.X4 -> BadgeSizeTokens(
minHeight = dimens.size.s200,
containerHorizontalPadding = dimens.spacing.s025,
containerVerticalPadding = dimens.spacing.none,
labelPadding = dimens.spacing.s025,
minHeight = 16.dp,
containerHorizontalPadding = 2.dp,
containerVerticalPadding = 0.dp,
labelPadding = 2.dp,
iconSize = 12.dp,
textStyle = typography.caption.medium,
)

View file

@ -108,7 +108,7 @@ fun TangemButton(
enabled = isEnabled,
color = backgroundColor,
border = resolveBorder(isFocused = isFocused, colorTokens = colorTokens, contentAlpha = contentAlpha),
shape = RoundedCornerShape(TangemTheme.dimens3.borderRadius.full),
shape = RoundedCornerShape(999.dp),
interactionSource = interactionSource,
isMaterial = variant == TangemButton.Variant.Material,
) {
@ -129,12 +129,12 @@ fun TangemButton(
@Composable
private fun resolveBorder(isFocused: Boolean, colorTokens: ColorTokens, contentAlpha: Float): BorderStroke? = when {
isFocused -> BorderStroke(
width = TangemTheme.dimens3.borderWidth.md,
width = 2.dp,
// Focus ring is intentionally NOT scaled by contentAlpha — see TangemButton above.
color = colorTokens.focusRingColor,
)
colorTokens.defaultBorderColor != null -> BorderStroke(
width = TangemTheme.dimens3.borderWidth.sm,
width = 1.dp,
color = colorTokens.defaultBorderColor.scaleAlpha(contentAlpha),
)
else -> null

View file

@ -282,7 +282,7 @@ internal fun TangemButton.Variant.tokens(): ColorTokens {
disabledTextColor = TangemTheme.colors3.text.primary,
disabledIconTint = TangemTheme.colors3.icon.primary,
focusRingColor = TangemTheme.colors3.interaction.focusRing.brand,
disabledAlpha = TangemTheme.dimens3.opacity.disabled,
disabledAlpha = 0.4f,
)
TangemButton.Variant.Material -> ColorTokens(
// Background is the haze fill (FILL/MATERIAL) rendered by TangemSurface when isMaterial = true;
@ -303,7 +303,7 @@ internal fun TangemButton.Variant.tokens(): ColorTokens {
disabledTextColor = TangemTheme.colors3.text.staticDark.primary,
disabledIconTint = TangemTheme.colors3.icon.staticDark,
focusRingColor = TangemTheme.colors3.interaction.focusRing.default,
disabledAlpha = TangemTheme.dimens3.opacity.disabled,
disabledAlpha = 0.4f,
)
TangemButton.Variant.Outline -> ColorTokens(
backgroundColor = Color.Transparent,
@ -313,7 +313,7 @@ internal fun TangemButton.Variant.tokens(): ColorTokens {
disabledTextColor = TangemTheme.colors3.text.primary,
disabledIconTint = TangemTheme.colors3.icon.primary,
focusRingColor = TangemTheme.colors3.interaction.focusRing.brand,
disabledAlpha = TangemTheme.dimens3.opacity.disabled,
disabledAlpha = 0.4f,
defaultBorderColor = TangemTheme.colors3.border.secondary,
)
TangemButton.Variant.Ghost -> ColorTokens(
@ -324,7 +324,7 @@ internal fun TangemButton.Variant.tokens(): ColorTokens {
disabledTextColor = TangemTheme.colors3.text.primary,
disabledIconTint = TangemTheme.colors3.icon.primary,
focusRingColor = TangemTheme.colors3.interaction.focusRing.brand,
disabledAlpha = TangemTheme.dimens3.opacity.disabled,
disabledAlpha = 0.4f,
)
}
}
@ -343,69 +343,68 @@ internal data class SizeTokens(
@Composable
@ReadOnlyComposable
internal fun TangemButton.Size.tokens(): SizeTokens {
val dimens = TangemTheme.dimens3
return when (this) {
TangemButton.Size.X14 -> SizeTokens(
minHeight = dimens.size.s700,
minWidth = dimens.size.s1100,
minSizeIconOnly = dimens.size.s700,
textPadding = dimens.spacing.s100,
containerHorizontalPadding = dimens.spacing.s200,
containerVerticalPadding = dimens.spacing.s200,
minHeight = 56.dp,
minWidth = 88.dp,
minSizeIconOnly = 56.dp,
textPadding = 8.dp,
containerHorizontalPadding = 16.dp,
containerVerticalPadding = 16.dp,
iconSize = 24.dp,
)
TangemButton.Size.X12 -> SizeTokens(
minHeight = dimens.size.s600,
minWidth = dimens.size.s1000,
minSizeIconOnly = dimens.size.s600,
textPadding = dimens.spacing.s100,
containerHorizontalPadding = dimens.spacing.s150,
containerVerticalPadding = dimens.spacing.s150,
minHeight = 48.dp,
minWidth = 80.dp,
minSizeIconOnly = 48.dp,
textPadding = 8.dp,
containerHorizontalPadding = 12.dp,
containerVerticalPadding = 12.dp,
iconSize = 24.dp,
)
TangemButton.Size.X11 -> SizeTokens(
minHeight = dimens.size.s550,
minWidth = dimens.size.s900,
minSizeIconOnly = dimens.size.s550,
textPadding = dimens.spacing.s075,
containerHorizontalPadding = dimens.spacing.s150,
containerVerticalPadding = dimens.spacing.s150,
minHeight = 44.dp,
minWidth = 72.dp,
minSizeIconOnly = 44.dp,
textPadding = 6.dp,
containerHorizontalPadding = 12.dp,
containerVerticalPadding = 12.dp,
iconSize = 20.dp,
)
TangemButton.Size.X10 -> SizeTokens(
minHeight = dimens.size.s500,
minWidth = dimens.size.s800,
minSizeIconOnly = dimens.size.s500,
textPadding = dimens.spacing.s075,
containerHorizontalPadding = dimens.spacing.s125,
containerVerticalPadding = dimens.spacing.s125,
minHeight = 40.dp,
minWidth = 64.dp,
minSizeIconOnly = 40.dp,
textPadding = 6.dp,
containerHorizontalPadding = 10.dp,
containerVerticalPadding = 10.dp,
iconSize = 20.dp,
)
TangemButton.Size.X9 -> SizeTokens(
minHeight = dimens.size.s450,
minWidth = dimens.size.s700,
minSizeIconOnly = dimens.size.s450,
textPadding = dimens.spacing.s075,
containerHorizontalPadding = dimens.spacing.s100,
containerVerticalPadding = dimens.spacing.s100,
minHeight = 36.dp,
minWidth = 56.dp,
minSizeIconOnly = 36.dp,
textPadding = 6.dp,
containerHorizontalPadding = 8.dp,
containerVerticalPadding = 8.dp,
iconSize = 20.dp,
)
TangemButton.Size.X8 -> SizeTokens(
minHeight = dimens.size.s400,
minWidth = dimens.size.s600,
minSizeIconOnly = dimens.size.s400,
textPadding = dimens.spacing.s075,
containerHorizontalPadding = dimens.spacing.s075,
containerVerticalPadding = dimens.spacing.s075,
minHeight = 32.dp,
minWidth = 48.dp,
minSizeIconOnly = 32.dp,
textPadding = 6.dp,
containerHorizontalPadding = 6.dp,
containerVerticalPadding = 6.dp,
iconSize = 20.dp,
)
TangemButton.Size.X7 -> SizeTokens(
minHeight = dimens.size.s350,
minWidth = dimens.size.s500,
minSizeIconOnly = dimens.size.s350,
textPadding = dimens.spacing.s075,
containerHorizontalPadding = dimens.spacing.s075,
containerVerticalPadding = dimens.spacing.s050,
minHeight = 28.dp,
minWidth = 40.dp,
minSizeIconOnly = 28.dp,
textPadding = 6.dp,
containerHorizontalPadding = 6.dp,
containerVerticalPadding = 4.dp,
iconSize = 16.dp,
)
}

View file

@ -139,12 +139,12 @@ fun TangemRow(
.conditionalCompose(divider) {
bottomDivider(
color = TangemTheme.colors3.border.secondary,
width = TangemTheme.dimens3.borderWidth.sm,
horizontalInset = TangemTheme.dimens3.spacing.s200,
width = 1.dp,
horizontalInset = 16.dp,
)
}
.conditionalCompose(includeInnerPaddings) {
padding(TangemTheme.dimens3.spacing.s200)
padding(16.dp)
},
) {
Row(
@ -164,7 +164,7 @@ fun TangemRow(
SideSlot(slot = endSlot, position = SideSlotPosition.End)
}
if (extraBottomSlot != null) {
SpacerH(TangemTheme.dimens3.spacing.s100)
SpacerH(8.dp)
extraBottomSlot()
}
}
@ -202,7 +202,7 @@ private enum class SideSlotPosition { Start, End }
@Composable
private fun SideSlot(slot: (@Composable BoxScope.() -> Unit)?, position: SideSlotPosition) {
if (slot == null) return
val spacing = TangemTheme.dimens3.spacing.s150
val spacing = 12.dp
val padding = when (position) {
SideSlotPosition.Start -> Modifier.padding(end = spacing)
SideSlotPosition.End -> Modifier.padding(start = spacing)
@ -297,7 +297,7 @@ private fun LabelColumnContent(
alignment: Alignment.Horizontal,
) {
Column(
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens3.spacing.s025),
verticalArrangement = Arrangement.spacedBy(2.dp),
horizontalAlignment = alignment,
) {
if (primary != null) LabelRow(alignment = alignment, content = primary)
@ -309,7 +309,7 @@ private fun LabelColumnContent(
private fun LabelRow(alignment: Alignment.Horizontal, content: @Composable RowScope.() -> Unit) {
Row(
horizontalArrangement = Arrangement.spacedBy(
space = TangemTheme.dimens3.spacing.s050,
space = 4.dp,
alignment = alignment,
),
content = content,
@ -399,10 +399,10 @@ private fun rowTextAlign(role: TangemRowTextRole): TextAlign = when (role) {
@Composable
private fun Modifier.focusBorder(): Modifier {
val radius = TangemTheme.dimens3.borderRadius.b200
val radius = 16.dp
val shape = remember(radius) { RoundedCornerShape(radius) }
return border(
width = TangemTheme.dimens3.borderWidth.md,
width = 2.dp,
color = TangemTheme.colors3.interaction.focusRing.default,
shape = shape,
)

View file

@ -88,7 +88,7 @@ fun TangemSearch(
TangemSurface(
modifier = Modifier
.weight(1f)
.heightIn(min = TangemTheme.dimens3.size.s550),
.heightIn(min = 44.dp),
isMaterial = true,
shape = CircleShape,
onClick = focusRequester::requestFocus,
@ -131,14 +131,14 @@ private fun SearchField(state: TangemSearch.State, focusRequester: FocusRequeste
modifier = Modifier
.weight(1f)
.padding(
start = TangemTheme.dimens3.spacing.s150,
top = TangemTheme.dimens3.spacing.s150,
bottom = TangemTheme.dimens3.spacing.s150,
start = 12.dp,
top = 12.dp,
bottom = 12.dp,
),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
modifier = Modifier.padding(end = TangemTheme.dimens3.spacing.s100),
modifier = Modifier.padding(end = 8.dp),
imageVector = Icons.ic_search_20,
tint = TangemTheme.colors3.icon.primary,
contentDescription = null,
@ -203,7 +203,7 @@ private fun QueryTextField(state: TangemSearch.State, focusRequester: FocusReque
Box {
if (state.query.isEmpty()) {
Text(
modifier = Modifier.padding(end = TangemTheme.dimens3.spacing.s250),
modifier = Modifier.padding(end = 20.dp),
text = placeholder,
style = sharedTextStyle,
color = TangemTheme.colors3.text.secondary,
@ -220,7 +220,7 @@ private fun QueryTextField(state: TangemSearch.State, focusRequester: FocusReque
@Composable
private fun ClearButton(onClick: () -> Unit) {
TangemButton(
modifier = Modifier.padding(end = TangemTheme.dimens3.spacing.s050),
modifier = Modifier.padding(end = 4.dp),
size = TangemButton.Size.X9,
variant = TangemButton.Variant.Ghost,
iconStart = TangemIconUM.Icon(Icons.ic_cross_circle_20_filled),
@ -233,7 +233,7 @@ private fun CloseButton(onClick: () -> Unit) {
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
TangemButton(
modifier = Modifier.padding(start = TangemTheme.dimens3.spacing.s100),
modifier = Modifier.padding(start = 8.dp),
size = TangemButton.Size.X11,
variant = TangemButton.Variant.Material,
iconStart = TangemIconUM.Icon(Icons.ic_cross_20),

View file

@ -62,7 +62,7 @@ fun TangemSurface(
color: Color = TangemTheme.colors3.bg.primary,
isMaterial: Boolean = false,
border: BorderStroke? = null,
shape: Shape = RoundedCornerShape(TangemTheme.dimens3.borderRadius.b200),
shape: Shape = RoundedCornerShape(16.dp),
onClick: (() -> Unit)? = null,
enabled: Boolean = true,
interactionSource: MutableInteractionSource? = null,
@ -123,7 +123,7 @@ private fun Modifier.materialShadow(shape: Shape): Modifier = softLayerShadow(
/** Diagonal gradient stroke that wraps the material variant. */
@Composable
private fun Modifier.materialBorder(shape: Shape): Modifier = border(
width = TangemTheme.dimens3.borderWidth.sm,
width = 1.dp,
brush = materialBorderBrush(),
shape = shape,
)
@ -145,7 +145,7 @@ private fun Modifier.materialFill(): Modifier {
val hazed = hazeEffectTangem(
style = HazeStyle(
backgroundColor = TangemTheme.colors3.material.fill.blur,
blurRadius = TangemTheme.dimens3.blur.Button,
blurRadius = 32.dp,
tints = emptyList(),
),
) {

View file

@ -84,16 +84,16 @@ fun TangemTopNavigation(
blur = blurBackground,
)
val groupSpacing = TangemTheme.dimens3.spacing.s100
val groupSpacing = 8.dp
Layout(
modifier = Modifier
.fillMaxWidth()
.windowInsetsPadding(windowInsets)
.padding(
top = TangemTheme.dimens3.spacing.s100,
bottom = TangemTheme.dimens3.spacing.s200,
start = TangemTheme.dimens3.spacing.s200,
end = TangemTheme.dimens3.spacing.s200,
top = 8.dp,
bottom = 16.dp,
start = 16.dp,
end = 16.dp,
),
content = {
// Each optional slot caches its last non-null content so the spring exit transition
@ -110,7 +110,7 @@ fun TangemTopNavigation(
Column(
modifier = Modifier
.padding(horizontal = TangemTheme.dimens3.spacing.s150)
.padding(horizontal = 12.dp)
.layoutId(SlotId.Content),
horizontalAlignment = when (contentAlign) {
TangemTopNavigation.ContentAlign.Start -> Alignment.Start
@ -130,7 +130,7 @@ fun TangemTopNavigation(
displayedGroup?.let { group ->
TangemSurface(isMaterial = true, shape = CircleShape) {
Row(
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens3.spacing.s050),
horizontalArrangement = Arrangement.spacedBy(4.dp),
content = group,
)
}
@ -307,7 +307,7 @@ private fun ColumnScope.TitleSubtitle(title: TextReference, subtitle: TextRefere
) {
displayedSubtitle?.let { text ->
Column {
Spacer(Modifier.height(TangemTheme.dimens3.spacing.s025))
Spacer(Modifier.height(2.dp))
TangemNavigationText(text = text, role = TangemNavigationText.Role.Subtitle)
}
}

View file

@ -30,7 +30,6 @@ 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
@ -201,11 +200,6 @@ object TangemTheme {
@ReadOnlyComposable
get() = LocalTangemDimens2.current
val dimens3: TangemDimens3
@Composable
@ReadOnlyComposable
get() = LocalTangemDimens3.current
val shapes: TangemShapes
@Composable
@ReadOnlyComposable
@ -406,10 +400,6 @@ private val LocalTangemDimens2 = staticCompositionLocalOf {
TangemDimens2()
}
internal val LocalTangemDimens3 = staticCompositionLocalOf {
TangemDimens3()
}
internal val LocalTangemTypography3 = staticCompositionLocalOf {
TangemTypography3(InterFamily)
}

View file

@ -7,7 +7,6 @@ import androidx.compose.foundation.text.selection.TextSelectionColors
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import com.tangem.core.ui.components.haze.ProvideHaze
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
@ -29,7 +28,6 @@ fun TangemThemeRedesign(content: @Composable () -> Unit) {
val rootBackgroundColor = rememberedColors.background.secondary
val tangemDimens3 = remember { TangemDimens3() }
val tangemTypography3 = remember { TangemTypography3(InterFamily) }
val tangemTypography2 = remember { TangemTypography2(InterFamily) }
val tangemTypography = remember { TangemTypography(InterFamily, useMediumForRegular = true) }
@ -42,7 +40,6 @@ fun TangemThemeRedesign(content: @Composable () -> Unit) {
LocalTangemColors provides rememberedColors,
LocalTangemColors2 provides if (LocalIsInDarkTheme.current) darkThemeColors2() else lightThemeColors2(),
LocalTangemColors3 provides rememberedColors3,
LocalTangemDimens3 provides tangemDimens3,
LocalTangemTypography3 provides tangemTypography3,
LocalTangemTypography2 provides tangemTypography2,
LocalTangemTypography provides tangemTypography,

View file

@ -1,110 +0,0 @@
@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,
val Fade: Dp = 8.dp,
val None: Dp = 0.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,
)
}

View file

@ -4,7 +4,18 @@ Generates Kotlin (Jetpack Compose) source files from design tokens defined in th
## Updating tokens
1. Update the `ds-tokens` submodule to the latest commit:
> **Note:** You only need `git submodule update --remote` when you want to pull **new** design tokens
> from the remote `ds-tokens` repository. If you're just regenerating Kotlin from the tokens already
> checked out (e.g. changing the generation script), **skip step 1** — don't run it without the need,
> as it moves the submodule pointer to the latest remote commit and pulls in unrelated token changes.
>
> For all other cases (a fresh checkout, or making sure the submodule is at the pinned commit), use:
> ```bash
> git submodule update --init --recursive
> ```
> This checks out the submodule at the commit already recorded in the repo, without pulling anything new.
1. *(Only if you need newer tokens)* Update the `ds-tokens` submodule to the latest commit:
```bash
git submodule update --remote core/ui/ds-tokens
```
@ -12,7 +23,7 @@ Generates Kotlin (Jetpack Compose) source files from design tokens defined in th
```bash
cd core/ui/token-gen && npm run build
```
3. Commit both the submodule pointer and generated files.
3. Commit the generated files (and the submodule pointer too, only if you ran step 1).
## How it works

View file

@ -202,46 +202,6 @@ function renderTree(node, indent = 1) {
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.
*/
@ -518,61 +478,6 @@ StyleDictionary.registerFormat({
},
});
/**
* 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-dimens3',
format: ({ dictionary }) => {
const prefix = 'TangemTheme.dimens3.';
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('.');
const raw = parseFloat(token.$value);
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.',
' */',
...classLines,
'',
].join('\n');
},
});
/**
* Kotlin format for TangemTypography3 @Stable class with nested categories.
* Generates a class taking FontFamily, with nested classes for each typography category
@ -849,8 +754,8 @@ const paletteSd = new StyleDictionary({
await paletteSd.buildAllPlatforms();
console.log(' ✓ TangemColorPalette.kt');
// Build theme-independent tokens (dimensions, typography)
console.log('\nBuilding dimension and typography tokens...');
// Build theme-independent tokens (typography)
console.log('\nBuilding typography tokens...');
const sd = new StyleDictionary({
source: sharedBuildSets.map(s => path.join(tokensDir, `${s}.json`)),
@ -862,10 +767,6 @@ const sd = new StyleDictionary({
transforms: composePlatformTransforms,
buildPath: outputDir + '/',
files: [
{
destination: 'TangemDimens3.kt',
format: 'kotlin/compose-dimens3',
},
{
destination: 'TangemTypography3.kt',
format: 'kotlin/compose-typography3',
@ -877,7 +778,6 @@ const sd = new StyleDictionary({
});
await sd.buildAllPlatforms();
console.log(' ✓ TangemDimens3.kt');
console.log(' ✓ TangemTypography3.kt');
// ── Write source hash ─────────────────────────────────────────────────────────

View file

@ -19,6 +19,7 @@ import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.SpacerW
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
@ -194,7 +195,7 @@ internal fun TransactionLabel(label: TransactionLabelUM, modifier: Modifier = Mo
modifier = modifier
.background(
color = backgroundColor,
shape = RoundedCornerShape(TangemTheme.dimens3.borderRadius.b250),
shape = RoundedCornerShape(20.dp),
)
.padding(
vertical = TangemTheme.dimens2.x3,

View file

@ -100,7 +100,7 @@ internal fun TangemPayAddCardView(onClick: () -> Unit, modifier: Modifier = Modi
height = TangemTheme.dimens2.x10,
width = TangemTheme.dimens2.x14,
)
.clip(RoundedCornerShape(TangemTheme.dimens3.borderRadius.b075))
.clip(RoundedCornerShape(6.dp))
.background(TangemTheme.colors3.bg.opaque.primary)
.clickableSingle(onClick = onClick),
contentAlignment = Alignment.Center,
@ -132,7 +132,7 @@ private fun CardBackground(
Box(
modifier = modifier
.clip(RoundedCornerShape(TangemTheme.dimens3.borderRadius.b075))
.clip(RoundedCornerShape(6.dp))
.drawBehind {
drawRect(bgColor)
@ -159,7 +159,7 @@ private fun CardBackground(
.border(
width = 1.dp,
color = TangemTheme.colors3.border.primary,
shape = RoundedCornerShape(TangemTheme.dimens3.borderRadius.b075),
shape = RoundedCornerShape(6.dp),
)
.clickableSingle(onClick = onClick),
content = content,

View file

@ -80,7 +80,7 @@ private fun ComponentPreview(state: TangemShimmerStory) {
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
.clip(RoundedCornerShape(TangemTheme.dimens3.borderRadius.b200))
.clip(RoundedCornerShape(16.dp))
.background(TangemTheme.colors3.bg.secondary)
.padding(vertical = 24.dp, horizontal = 16.dp),
) {
@ -145,7 +145,7 @@ private fun ChipSection(label: String, content: @Composable () -> Unit) {
@Composable
private fun <T> ChipGrid(items: List<T>, label: (T) -> String, isSelected: (T) -> Boolean, onSelect: (T) -> Unit) {
val shape = RoundedCornerShape(TangemTheme.dimens3.borderRadius.full)
val shape = RoundedCornerShape(999.dp)
Row(
modifier = Modifier
.fillMaxWidth()
@ -153,7 +153,7 @@ private fun <T> ChipGrid(items: List<T>, label: (T) -> String, isSelected: (T) -
.clip(shape)
.background(TangemTheme.colors3.bg.opaque.primary)
.border(
width = TangemTheme.dimens3.borderWidth.sm,
width = 1.dp,
color = TangemTheme.colors3.border.primary,
shape = shape,
)
@ -173,7 +173,7 @@ private fun <T> ChipGrid(items: List<T>, label: (T) -> String, isSelected: (T) -
@Composable
private fun Chip(label: String, selected: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
val chipShape = RoundedCornerShape(TangemTheme.dimens3.borderRadius.full)
val chipShape = RoundedCornerShape(999.dp)
Box(
contentAlignment = Alignment.Center,
modifier = modifier