feat(component): add button style tokens (UI Kit 5.0)#29
Conversation
Adds the button component style tokens from the UI Kit 5.0 Button page so
consumers (SDUI V4 CTAs, native button components) share one source of truth.
Definition (tokens/definitions/component/button.json) is decomposed and references
existing semantic tokens:
- variants: primary/secondary/tertiary/ghost map to semantic.color.action.*
(+ border.default for tertiary); inverse → surface.elevated/text.primary;
disabled → action.disabled/disabledContent
- sizes 48/40/32: height, cornerRadius (= height/2, pill), padding, and the
subtitle label font (s1/s2/s3)
- pressedInset: 1 (the pressed state is a 1px client inset, not a color)
Build emits `nucleus-button.json` (combined `component.button.{variant}.{size}`
styles, colors/fonts as token paths) and a `ButtonStyleToken` literal-union type.
Stacked on the TS-types PR. Native (iOS/Android) style-constant generators are a
fast follow — the button colors already generate to NucleusColor.action*, and the
definition here is the platform-agnostic source. `inverse` maps to
surface.elevated/text.primary pending a dedicated inverse action token.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
UI Kit 4.0 names the category 'Number' and has no 'caption'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jaidensiu
left a comment
There was a problem hiding this comment.
are these tokens meant to be used cross platform? seems like only web tokens are being generated currently
# Conflicts: # tokens/formats/types-web.ts
Makes button tokens cross-platform (was web-only). Each `component.button.
{variant}.{size}` now also emits:
- iOS: a new `NucleusButtons` SPM target — `NucleusButton` struct + generated
`NucleusButton+Defaults.swift` (`static let primary48`, …) referencing the
theme-aware `NucleusColor` and `NucleusFont` tokens.
- Android: generated `NucleusButtons.kt` — `NucleusButtonStyle` + a theme-aware
`NucleusButtonColor(light, dark)` pair referencing the existing
`NucleusSemanticColorsLight`/`Dark` objects + `NucleusFonts`.
Colors/fonts are referenced (not duplicated), so the button styles stay in sync
with the semantic tokens. Buttons remain style *tokens*; the button *view* is
left to the consumer (like `NucleusCard`).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a0f8ee253a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| /** Theme-aware color pair referencing the existing semantic-color objects. */ | ||
| function colorExpr(path: string): string { | ||
| const accessor = colorAccessor(path); | ||
| return `NucleusButtonColor(NucleusSemanticColorsLight.${accessor}, NucleusSemanticColorsDark.${accessor})`; |
There was a problem hiding this comment.
Wrap generated Android color expressions
For button tokens whose semantic accessor names are long (for example actionPrimaryContent), this one-line template emits committed Kotlin lines up to 138 characters in NucleusButtons.kt; android/.editorconfig sets max_line_length = 120 and the verify workflow runs ./gradlew :nucleus:check, while ktlint documents that its max-line-length rule enforces the configured max_line_length setting (https://pinterest.github.io/ktlint/latest/rules/standard/#max-line-length). This makes the Android check fail for this commit unless the generator wraps these constructor arguments or suppresses the generated file.
Useful? React with 👍 / 👎.
…-char limit The one-line NucleusButtonColor(light, dark) pairs produced committed Kotlin lines up to 138 chars, which would fail `./gradlew :nucleus:check` (android/.editorconfig max_line_length = 120). Wrap each color pair across lines; longest line is now 92. Addresses Codex review feedback. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Chef's kiss. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
| import androidx.compose.ui.unit.Dp | ||
| import androidx.compose.ui.unit.dp | ||
|
|
||
| /** A theme-aware color pair for a button token. */ |
There was a problem hiding this comment.
nit: can we use multiline kdocs where necessary? it would be best to upkeep our API docs as we scale our design system 🙏
| @@ -0,0 +1,85 @@ | |||
| import { camelCasePath, publicColorPath } from './shared.js'; | |||
There was a problem hiding this comment.
can we put the templating on handlebars to be consistent with the rest of the generators?
| @@ -0,0 +1,48 @@ | |||
| import { camelCasePath, publicColorPath } from './shared.js'; | |||
There was a problem hiding this comment.
same with the android-equiv, can we use handlebars here for templating?
What
Adds the button component style tokens from the UI Kit 5.0 Button page, so SDUI V4 CTAs and native button components share one source of truth. Extracted from the Button page: Variant (Primary/Secondary/Tertiary/Ghost/Inverse) × Size (48/40/32) × State (Default/Pressed/Disabled).
Model
tokens/definitions/component/button.jsonis decomposed and references existing semantic tokens (no new color values):action.primaryaction.primaryContentaction.secondaryaction.secondaryContentaction.tertiaryaction.tertiaryContentborder.defaultaction.ghostaction.ghostContentsurface.elevatedtext.primaryaction.disabledaction.disabledContentSizes (pill, radius = height/2; label = subtitle font):
s1s2s3pressedInset: 1— pressed is a 1px client inset, not a separate color.Build output
build/web/nucleus-button.json— combinedcomponent.button.{variant}.{size}styles (18 = 6×3), colors/fonts as token paths so they stay theme-aware.ButtonStyleTokenliteral-union added to the generatedindex.d.ts.formats/buttons.ts,build/buttons.ts; sharedtypographyTokenPathhelper; build wiring.npm run build,typecheck,lint,format:checkall pass.Notes for review
inversemaps tosurface.elevated/text.primary— there is noaction.inversetoken. Flag if a dedicated one is wanted.ghostcontent usesaction.ghostContent(theme-aware); the Figma frame renders white because Ghost previews on a dark surface.NucleusColor.action*, and this definition is the platform-agnostic source. Consistent with native components (e.g.NucleusCard) being hand-written.Part of adopting Nucleus tokens in app-backend SDUI V4.
🤖 Generated with Claude Code