Skip to content

feat(component): add button style tokens (UI Kit 5.0)#29

Open
Gr1dlock wants to merge 5 commits into
feat/ts-token-typesfrom
feat/component-button-tokens
Open

feat(component): add button style tokens (UI Kit 5.0)#29
Gr1dlock wants to merge 5 commits into
feat/ts-token-typesfrom
feat/component-button-tokens

Conversation

@Gr1dlock
Copy link
Copy Markdown
Contributor

@Gr1dlock Gr1dlock commented Jun 2, 2026

Stacked on #27 (TS types). Review/merge that first; base retargets to main after.

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.json is decomposed and references existing semantic tokens (no new color values):

variant background content border
primary action.primary action.primaryContent
secondary action.secondary action.secondaryContent
tertiary action.tertiary action.tertiaryContent border.default
ghost action.ghost action.ghostContent
inverse surface.elevated text.primary
disabled action.disabled action.disabledContent

Sizes (pill, radius = height/2; label = subtitle font):

size height radius padding (h×v) font
48 48 24 24×12 s1
40 40 20 20×10 s2
32 32 16 16×6 s3

pressedInset: 1 — pressed is a 1px client inset, not a separate color.

Build output

  • build/web/nucleus-button.json — combined component.button.{variant}.{size} styles (18 = 6×3), colors/fonts as token paths so they stay theme-aware.
  • ButtonStyleToken literal-union added to the generated index.d.ts.
  • New: formats/buttons.ts, build/buttons.ts; shared typographyTokenPath helper; build wiring.

npm run build, typecheck, lint, format:check all pass.

Notes for review

  • inverse maps to surface.elevated/text.primary — there is no action.inverse token. Flag if a dedicated one is wanted.
  • ghost content uses action.ghostContent (theme-aware); the Figma frame renders white because Ghost previews on a dark surface.
  • Native (iOS/Android) generators are a fast follow — button colors already generate to 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

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>
Copy link
Copy Markdown
Collaborator

@jaidensiu jaidensiu left a comment

Choose a reason for hiding this comment

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

are these tokens meant to be used cross platform? seems like only web tokens are being generated currently

Gr1dlock and others added 2 commits June 5, 2026 15:49
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>
@Gr1dlock
Copy link
Copy Markdown
Contributor Author

Gr1dlock commented Jun 5, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 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".

Comment thread tokens/formats/buttons-android.ts Outdated
/** 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})`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge 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>
@Gr1dlock
Copy link
Copy Markdown
Contributor Author

Gr1dlock commented Jun 5, 2026

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

ℹ️ 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".

import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

/** A theme-aware color pair for a button token. */
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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';
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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';
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

same with the android-equiv, can we use handlebars here for templating?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants