Skip to main content
Current version: 0.4.7. Source: packages/carto-tokens/CHANGELOG.md.

0.4.7

Patch Changes

  • #3064 3e36538 Thanks @rollsroyc3! - [Tokens] Add text.highlight.backgroundFallback, a solid stand-in for text.highlight.background (web’s gradient) on React Native, Swift, and Kotlin, which cannot render it. [Text] Consume backgroundFallback for the highlighted prop’s background instead of a hardcoded rgba(188, 226, 234, 0.4) literal.

0.4.6

Minor Changes

Patch Changes

  • #2922 65336ab Thanks @ericag1985! - [Tokens] Remove unused Button elevation and zero-width border tokens now that both kits are flat and borderless

0.4.5

Minor Changes

  • #2862 dc20f1d Thanks @rollsroyc3! - [Button] Add the large size and the danger-secondary variant to the React Native kit, with the critical-subdued semantic intents behind them.

0.4.4

Minor Changes

  • #2828 24c1d47 Thanks @w-a-t-s-o-n! - [Tokens] Add a mobile theme overlay so React Native, Swift, and Kotlin can override token values independently of web, fully round button.radius, and emit radius.contained on Swift and Kotlin.

0.4.3

Patch Changes

0.4.2

Minor Changes

  • #2729 84ff49a Thanks @jpex! - [Suggestion] Restyle the chip surface to match Card — standard fill, 1px standard border, and hover-only ambient elevation

0.4.1

Patch Changes

  • #2669 21efe99 Thanks @w-a-t-s-o-n! - Fix two latent build-pipeline bugs found during review. normalizeFlatTokens’s chainsAppearance propagation was a single forward sweep over the token array instead of a fixed point, so a same-tier transitive alias chain of three or more hops could fail to propagate depending on declaration order. The only consumer, the Kotlin emitter, uses this flag to pick a token’s declared type — a false negative would emit a val whose declared type doesn’t match the value it points to, which doesn’t compile. Separately, emitReactNativeFile inlined semantic-to-semantic self-referencing aliases to avoid a self-referential const initializer, but never applied the same guard to component-to-component aliases — an alias between two component tokens would generate a const that references itself inside its own initializer, throwing a ReferenceError at module load. Neither bug is triggered by any token currently in src/, so this release’s generated output is unchanged. Both are correctness fixes to the pipeline itself, each covered by a new regression test.
  • #2669 21efe99 Thanks @w-a-t-s-o-n! - Publish @servicetitan/carto-tokens from the Hammer monorepo. The package moved here as a fresh import from the carto repo at 8dc7f861, at the same 0.4.0 it was last published from carto. Token values, exports, and the --carto-* variable namespace are all unchanged — this is a change of publishing origin, not of anything a consumer imports. A patch is therefore the honest bump: the next release exists only so Hammer’s pipeline can take over from carto’s, and consumers upgrading from 0.4.0 get identical output.

0.4.0

Major Changes

  • #288 aa78524 Thanks @w-a-t-s-o-n! - Do not use the previous version in this package’s changelog. For packages versioned in #287, that entry was merged to main but never successfully published (@servicetitan/anvil2-charts-kit@0.0.2, @servicetitan/anvil2-rn-charts-kit@0.1.0, @servicetitan/anvil2-ai-kit@0.8.4, @servicetitan/anvil2-rn@0.0.10). Several of those numbers (and other unpublished builds) are permanently reserved after a security-related npm unpublish and cannot be republished. Bump package versions past the reserved numbers. Upgrade to the versions from this release; do not pin to the removed or unpublished ones.

Minor Changes

  • #283 debb29f Thanks @ericag1985! - [tooltip] Restyle the tooltip surface to the new Carto design — a blue 900 background and an 8px corner radius

0.3.0

Major Changes

  • #246 ced2173 Thanks @ericag1985! - [Tokens] Rename font.family.satoshi primitive to font.family.sofia (now ["Sofia Pro", "system-ui", "sans-serif"]); consumers referencing primitive.font.family.satoshi directly must switch to primitive.font.family.sofia

Minor Changes

  • #246 ced2173 Thanks @ericag1985! - [Tokens] Add component.suggestion.background and component.tabbedLayout.tab.background (resting/hover, aliasing the same subtle wash as button.secondary); repoint component.userMessage.bubble.background to the same wash

Patch Changes

  • #246 ced2173 Thanks @ericag1985! - [Button] Update button.primary and button.secondary component tokens for new visual treatment
  • #246 ced2173 Thanks @ericag1985! - [Tokens] Remove unused card.elevation.resting; add card.border.color and card.border.width
  • #246 ced2173 Thanks @ericag1985! - [Tokens] Update typography.fontFamily.expressive to resolve to Sofia Pro and consolidate all text.headline.* (regular/substantial/major/hero) fontWeight aliases to typography.weight.emphatic (Bold), matching the Sofia Pro Bold-only headline treatment
  • #246 ced2173 Thanks @ericag1985! - [Tokens] Add text.highlight.background component token, aliasing background.color.informative-subdued.resting

0.2.4

Minor Changes

  • #236 15a46a4 Thanks @ericag1985! - [Tokens] Add component.button.toggle.selected tokens for ButtonToggle’s resting, hover, and pressed selected state

0.2.3

Minor Changes

  • #174 78d6ae5 Thanks @w-a-t-s-o-n! - [Tokens] Add semantic component tokens for GuidanceCard spacing, reason callout, and actions
  • #171 6c6b726 Thanks @tounsoo! - Add a React Native token output target. @servicetitan/carto-tokens/react-native exports light and dark theme bundles (each with primitive/semantic/component tiers) as plain as const objects, plus a CartoTheme type. Dimensions are unitless numbers, alpha is baked into #rrggbbaa, shadows are boxShadow strings, and appearance is pre-resolved into the two bundles — select via useColorScheme().

Patch Changes

  • #174 78d6ae5 Thanks @w-a-t-s-o-n! - [Tokens] Add semantic tokens for presentational table surfaces, borders, and cell spacing

0.2.2

Minor Changes

Patch Changes

  • #145 4fc2468 Thanks @tounsoo! - [AppShell, BottomSheet, Button, Card, Citation, Dialog, Link, Menu, PromptBar, TabbedLayout, UserMessage, Window] Drive motion from semantic motion tokens instead of inlined curves. Hover/press/focus acknowledgments now use the faster feedback duration (100ms, down from 200ms), panel and overlay transitions use the emphasis duration with directional enter/exit easing, and easing curves shift to the semantic motion values. Animation timings and curves change as a result. [Tokens] Retarget the bottom-sheet and dialog focus-ring transition.duration from motion.duration.transition to motion.duration.feedback (200ms to 100ms).
  • #185 b9aed02 Thanks @tounsoo! - [Tokens] Add agentThinking.gap and agentThinking.foreground component tokens
  • #190 ab27e8c Thanks @ericag1985! - [Button] Button label text now renders in medium weight (Inter Medium).

0.2.1

Minor Changes

  • #160 8d837f1 Thanks @tounsoo! - Citation now renders a 1px solid white hairline border. Adds a new citation.border.color component token that aliases primitive neutral 0 (white) directly, so the border stays white in both light and dark appearances.
  • #162 d6044e5 Thanks @tounsoo! - Tokenize PromptInput and the AgentPrompt header foreground.
    • carto-tokens — adds agentPrompt.header.foreground (aliases foreground.color.standard) and a new prompt-input.tokens.json with promptInput.font (composite typography), promptInput.foreground, promptInput.placeholder.foreground, and promptInput.disabled.foreground.
    • carto-react-kit — wires the AgentPrompt question heading to the new header token, and routes PromptInput’s text, placeholder, disabled, and typography through the new component tokens (previously raw primitive.font.* and direct semantic.* references). All values are unchanged, so there is no visual change.

Patch Changes

  • #138 cb8458d Thanks @tounsoo! - [Tokens] Replace Style Dictionary with a native build pipeline. Token output is byte-for-byte identical, so there is no consumer-facing change.
  • #163 fd6c97e Thanks @tounsoo! - [Tokens] Author font.family.* as ordered DTCG font stacks (arrays). Web joins the stack into a CSS font-family list (output unchanged), while Figma, Swift, and Kotlin now take the primary family only instead of the full comma-separated string.

0.2.0

Major Changes

  • #125 42b5ac6 Thanks @tounsoo! - [Tokens] Group the semantic motion tokens under a single motion namespace. The duration, scale, and easing semantic groups are consolidated into one motion.tokens.json and nested as motion.duration.*, motion.scale.*, and motion.easing.*. Their previous top-level names collided conceptually with the primitive duration/scale ramps and implied generic, non-motion use; grouping them under motion matches the existing semantic-naming convention (size → spacing, color → background) and frees the top-level duration/scale namespaces for future non-motion intents. BREAKING: consumers must migrate duration.* → motion.duration.*, scale.* → motion.scale.*, and easing.* → motion.easing.*. Web: --ct-duration-*/--ct-scale-*/--ct-easing-* become --ct-motion-duration-*/--ct-motion-scale-*/--ct-motion-easing-*. Swift/Kotlin: Semantic.{Duration,Scale,Easing} move under Semantic.Motion.{Duration,Scale,Easing}. The primitive duration/scale ramps are unchanged.

Minor Changes

  • #123 c8b8b28 Thanks @tounsoo! - [Tokens] Add agentPrompt.* component tokens for the AgentPrompt surface — the card (background, border.color, radius, elevation, padding, gap), region spacing (header.gap, options.gap, actions.gap), the option rows (option.background.{resting,hover,pressed}, option.foreground, option.padding, option.radius, option.selected.border.color), the multi-select checkbox indicator (checkbox.border.color, checkbox.foreground, checkbox.selected.background), the step counter (stepCount.foreground), and the empty-answer error (error.foreground, error.gap), each aliasing the semantic tier. Also adds a semantic opacity.disabled (0.6) token. AgentPrompt now consumes these via the component.agentPrompt.* proxy instead of reaching into semantic.* directly. As part of this:
    • Option rows are now proper interactive surfaces: their background uses background.color.subtle.{resting,hover,pressed} (replacing the prior translucent rgba(4,4,4,…) fills) with the paired foreground.color.on.subtle text color.
    • The disabled-dim opacity is now the shared opacity.disabled token; the option rows shift from 0.5 to the system 0.6.
    • The focus ring adopts the semantic focus tier (focus.width / focus.color / focus.offset), shifting the ring thickness from a hard-coded 2px to the system 3px.
  • #139 ca506f0 Thanks @tounsoo! - [Tokens] Add artifactCard.* component tokens for the ArtifactCard surface — foreground (the title/description/arrow color, aliasing foreground.color.standard), gap (the horizontal rhythm between the lead cluster and the trailing arrow, and between the icon and text, aliasing spacing.base), and text.gap (the title↔description lockup, aliasing spacing.micro). ArtifactCard now consumes these via the component.artifactCard.* proxy instead of reaching into semantic.*/primitive.* directly. No visual change: the title↔description gap was already 4px (primitive.size["100"]), now expressed as the matching spacing.micro intent.
  • #126 d5c6c81 Thanks @tounsoo! - [Tokens] Add the bottomSheet component token set, aliasing the semantic tier: surface.{background,foreground,radius,elevation}, padding.{inline,block.end}, gap, header.{gap,padding.inline}, subheader.foreground, handle.padding.block.{start,end}, handle.grip.{width,height,radius,background}, focus.ring.{color,width,offset}, and focus.ring.transition.{duration,easing} (aliasing motion.duration.transition / motion.easing.transition — the everyday color-shift motion intent; excludePlatforms: figma). handle.grip.background is a provisional gap (primitive {color.neutral.400} — no foreground/handle intent matches it yet); handle.grip.{width,height} are intentional primitives ({size.900} / {size.100}). [React Kit] BottomSheet now consumes its component.bottomSheet.* tokens instead of inline semantic/primitive literals. Visual changes adopted from the token mappings: top corners use the large-container radius.generous (24px, up from 12px); the surface elevation and text pair with the standard surface; the drag-handle focus-ring offset normalizes to the system 2px (was 4px); and the now-shipped focus.* tokens back both the grip and body focus rings. The vestigial 1px top hairline (not in the Figma spec) is removed — the drop shadow alone separates the sheet from the backdrop. The shared modal backdrop now consumes semantic.scrim.color (no visual change). The body focus-ring fade now consumes focus.ring.transition.{duration,easing} (200ms / cubic-bezier(0.4, 0, 0.2, 1)); its easing adopts the motion.easing.transition curve, shifting from the kit’s inline [0,0,0.4,1] — making BottomSheet the first consumer of the motion tokens.
  • #108 011c6ea Thanks @tounsoo! - [Tokens] Add per-variant button.<variant>.border.width tokens (secondary → size.25 / 1px, primary / ghost / danger → size.0) so the borderless variants gain border capability without changing their current footprint. Button’s secondary variant now consumes its width token directly — replacing the prior hard-coded 1px literal — and subtracts it from the padding so the bordered variant keeps the same outer size as the borderless ones (which stay at border-width: 0).
  • #135 c00c7d5 Thanks @tounsoo! - [Tokens] Add the card component token set, aliasing the semantic tier: card.background.{resting,hover} ({background.color.standard.*}), card.radius ({radius.moderate}), card.elevation.{resting,hover} ({shadow.ambient.resting} / {shadow.ambient.hover}), card.padding.{snug,base,relaxed} ({spacing.*}), and card.focus.ring.{color,width,offset} ({focus.*}). No visual change — these formalize the values Card already uses (resting + hover elevation now route through the shadow.ambient family). [React Kit] Card.css.ts now consumes component.card.* instead of reaching into semantic.* directly. The disabled state consumes semantic.opacity.disabled, and the in-place transition consumes semantic.motion.duration.transition + semantic.motion.easing.transition — adopting the semantic ease-in-out curve (cubic-bezier(0.4, 0, 0.2, 1)) in place of the prior inlined cubic-bezier(0, 0, 0.4, 1) (duration unchanged at 200ms). Only the highlight gradient remains inline as a flagged gap (gradients have no DTCG representation).
  • #128 df50037 Thanks @tounsoo! - [Citation] Add citation component tokens aliasing the semantic tier: background (resting subtle, hover informative-subdued), foreground (resting standard, hover informative), composite font typography, gap, inline padding, radius, and the focus.ring (color/width/offset). Light/dark inherits from the semantic aliases.
  • #137 ec0c239 Thanks @tounsoo! - [Tokens] Add the dialog component token set, aliasing the semantic tier: overlay.padding, surface.{background,foreground,border.color,border.width,radius,elevation}, padding, gap, header.gap, footer.gap, focus.ring.{color,width,offset}, and focus.ring.transition.{duration,easing} (aliasing motion.duration.transition / motion.easing.transition — the everyday color-shift motion intent; excludePlatforms: figma). Values cross-checked against Figma (Carto Web Components, node 787:3308): width 360px, padding/gap 24px, header gap 8px, footer gap 12px, background white all match. Adopted value shifts (semantic intent over the Figma literal): surface.border.color aliases {border.color.subtle} (neutral.30, #f6f6f6, from Figma’s #e6e6e6); surface.radius aliases {radius.generous} (24px, from Figma’s 12px) to match BottomSheet’s panel radius. surface.elevation aliases {shadow.floating.resting} (the shared transient-surface intent; blur follows the semantic token). surface.border.width is {size.25} (1px). [React Kit] Dialog now consumes its component.dialog.* tokens instead of inline semantic/primitive literals. The surface foreground pairs with the standard surface (foreground.color.on.standard, same neutral.800 value — no visual change). The body focus-ring fade now consumes focus.ring.transition.{duration,easing} (200ms / cubic-bezier(0.4, 0, 0.2, 1)); its easing adopts the motion.easing.transition curve, shifting from the prior inline [0,0,0.4,1] to match BottomSheet + Button. The fixed 360px surface width stays an intentional raw literal (no semantic intent, no matching size primitive); zIndex: 1000 is kept raw on purpose (Carto has no layering token scale yet); the shared modal backdrop continues to consume semantic.scrim.color.
  • #110 71b7210 Thanks @tounsoo! - [Tokens] Add a global focus semantic category — focus.width ({size.75}, the new 3px primitive rung), focus.offset ({size.50}, 2px), and focus.color ({border.color.accent}) — so every focus ring shares one system-wide treatment. button.focus.ring.{color,width,offset} now alias focus.* (no visual change: still #0265dc, 3px, 2px offset), and the new size.75 = 3px primitive backs the ring width. [React Kit] Dialog (body scroll region) and PromptBar (disclaimer link) now consume the global semantic.focus.* tokens instead of inline outline literals. The Dialog ring is unchanged (3px / 2px / accent); the PromptBar disclaimer-link ring grows from 2px to the global 3px width so it matches every other focus ring.
  • #129 b1a78a4 Thanks @tounsoo! - [Tokens] Add link component tokens that alias the semantic tier: link.foreground.resting ({foreground.color.standard}) and link.foreground.hover ({foreground.color.informative}) for the link’s text color, link.radius ({radius.trim}) for the focus-ring corner, and link.icon.gap ({spacing.micro}) for the trailing external-link icon’s lockup. Link’s recipe now consumes these tokens in place of the raw semantic.* / primitive.* references it used before — all value-preserving, no rendered change. The shared focus-ring (component.button.focus.ring.*) and the inline transition curve are unchanged: the ring is still the kit’s single button-owned definition consumed directly, and motion adoption stays deferred pending the curve-shift decision (matching Button).
  • #134 c083c3c Thanks @tounsoo! - [Tokens] Add menu.* component tokens for the Menu surface and options — the popover (surface.background, surface.radius, surface.elevation), the option list (list.gap, list.padding), the option rows (option.background.{resting,hover,pressed}, option.foreground.resting, option.gap, option.radius, option.padding.{inline,block}, option.opacity.disabled), the selected option (option.selected.background.{resting,hover,pressed}, option.selected.foreground.{resting,hover,pressed}), and the focus ring (focus.ring.color, focus.ring.width), each aliasing the semantic tier. [Tokens] Extend the semantic tier so the Menu’s selected states alias real intents instead of raw primitives:
    • background.color.informative-subdued is promoted from a scalar to a stateful group — resting (blue.50), hover (blue.100), pressed (blue.200).
    • foreground.color.on.informative-subdued is added — resting (blue.600), hover (blue.700), pressed (blue.800) — the on-color paired with the informative-subdued surface.
    Citation’s hover surface moves to the .resting leaf with no value change (background.color.informative-subdued → .resting). Menu now consumes these via the component.menu.* proxy instead of reaching into semantic.* / primitive.* directly. As part of this:
    • The popover surface uses radius.moderate (16px) and the option rows use radius.trim (12px), matching the Figma bindings (semantic/radius/moderate on the container, semantic/radius/trim on the options).
    • The disabled-dim opacity is now the shared opacity.disabled token (replacing a hard-coded 0.6).
    • The selected option surfaces/text alias background.color.informative-subdued.{resting,hover,pressed} and foreground.color.on.informative-subdued.{resting,hover,pressed} (no more color.blue.* primitive interims).
    • The unselected option uses the ghost surface intent — background.color.ghost.{resting,hover,pressed} — paired with foreground.color.on.ghost text (neutral.800, a deliberate shift from Figma’s foreground/color/default #040404, which has no carto equivalent).
    Cross-checked against Figma (node 43:290): popover background/elevation/radius, option spacing/typography, the selected-state surfaces/text, and the 180/360px width mechanics all match. The new informative-subdued / on.informative-subdued hover values (blue.100 #cce3ff, blue.700 #1d4ca3) equal Figma’s primary-subdued-hover / primary-hover. The unselected option’s hover/press tints intentionally use the translucent ghost intent (neutral.400 @ 0.08/0.16) rather than Figma’s opaque standard.hover (#f9f9f9). The option pressed/active states are kept from the RAC/anvil2 interaction model but are beyond the Figma spec, which defines only default/hover/disabled. Remaining gap: the popover min/max width (180/360px) stay raw literals in the recipe as no width scale exists at any tier.
  • #127 07e28ca Thanks @tounsoo! - [Tokens] Add a @servicetitan/carto-tokens/motion export: raw, JS-native values for the motion.* token namespace, intended for Framer Motion (motion) and other JS consumers that can’t use CSS custom properties. The vanilla-extract output exposes motion tokens only as CSS variables (cubic-bezier(...) strings, ms time literals), which Motion’s JS API rejects — its ease prop wants a [x1, y1, x2, y2] tuple and its duration prop wants a unitless number in seconds. The new module exports easing (cubic-bezier control-point tuples, typed as CubicBezier), duration (numbers in seconds, e.g. 200ms → 0.2), and scale (unitless multipliers), plus a combined motion object. Values are generated from the same token source as the CSS variables, so the two surfaces stay in sync.
  • #136 5bf6962 Thanks @tounsoo! - [Tokens] Add shadow.ambient — a new low rung on the elevation scale for a subtle interactive affordance. Unlike the directional raised/floating shadows, ambient is a soft, diffuse shadow that sits flush to the surface with no offset (neutral.800 @ 4% resting / 8% hover, blur {size.400}), signalling an element is interactive without pronounced elevation. New ladder: flush (0) → ambient (4%) → raised (12%) → floating (24%). flush, raised, and floating are unchanged (same values and Figma variable IDs), so existing consumers are unaffected. [React Kit] Card now consumes semantic.shadow.ambient.{resting,hover} for its resting and hover elevation, replacing the inline custom ambient shadow (the resting value is identical, resolving the long-standing TODO(carto-tokens)) and the prior raised.resting hover (12% → ambient 8%, a softer hover lift).
  • #104 11a4c84 Thanks @AdamLantz! - [Tokens] Add appShell component tokens: appShell.region.background and appShell.handle.background.hover/appShell.handle.background.pressed for the resize handle.

Patch Changes

  • #112 5604d96 Thanks @tounsoo! - [Tokens] Fix the Android (Compose) build failing to compile the generated CartoTokens.kt. The easing category emits an enclosing object Easing whose name shadowed the unqualified Easing type annotation, so every cubicBezier leaf failed with Initializer type mismatch: expected 'Easing', actual 'CubicBezierEasing'. The Kotlin generator now imports the Compose type aliased as ComposeEasing (mirroring the existing ComposeColor pattern) and uses it for cubicBezier leaf types.

0.1.2

Minor Changes

  • #59 2b25a96 Thanks @tounsoo! - [Tokens] Add button component tokens (primary / secondary / ghost backgrounds, foregrounds, elevation; font, gap, padding, radius, and focus) and wire Button to consume them via the component proxy instead of hard-coded primitives. The button’s icon size consumes the existing icon.size.large token directly (no redundant button.icon alias)
  • #85 69c049c Thanks @tounsoo! - [Tokens] Add button.danger component tokens (background, foreground, elevation) aliasing the critical semantic surface, and wire the Button danger variant to consume them via the component proxy instead of reading semantic.* critical tokens directly
  • #77 987b206 Thanks @tounsoo! - [Tokens] Add the border.color.accent semantic intent (brand-interactive outline for focus rings, active navigation, and selected controls) and restructure the button’s focus tokens into a button.focus.ring group (color → border.color.accent, plus width and offset). Button now consumes button.focus.ring.{color,width,offset} for its focus ring instead of a primitive color alias and an inline outline width. No visual change — the ring stays #0265dc, 3px thick, 2px offset.
  • #83 fdcc420 Thanks @tounsoo! - [PromptBar] Add promptBar component tokens and wire the recipe to consume them New semantic-aliasing component tokens (promptBar.*) cover the bar surface (background, border, radius, elevation, gap, padding), the attachment tile, the disclaimer, and the error foreground. The PromptBar recipe now consumes component.promptBar.* instead of referencing semantic/primitive directly. Values map 1:1 from the prior references except the attachment-tile background, which adopts background.color.subtle.resting (neutral.30 → neutral.50) and now follows light/dark.
  • #102 3bcff52 Thanks @tounsoo! - [Tokens] Add duration semantic category — motion durations chosen by the significance of the moment. Five static leaves aliasing the duration primitives: duration.instant ({duration.0}), duration.feedback ({duration.100}), duration.transition ({duration.200}), duration.emphasis ({duration.300}), duration.cinematic ({duration.400}). Mode-agnostic (no light/dark) and excludePlatforms: ["figma"], mirroring the primitive tier.
  • #106 8cad2e0 Thanks @tounsoo! - [Tokens] Add easing semantic category — five intent-named cubic-bezier curves (enter, exit, transition, loop, emphasis) that name the character of acceleration across a motion, chosen by behavior rather than a hardcoded bezier. Introduces a new cubicBezier $type with web (cubic-bezier(...)), Swift ((CGFloat, CGFloat, CGFloat, CGFloat) tuple), and Kotlin (Compose CubicBezierEasing) transforms. Static, no light/dark, excludePlatforms: ["figma"] (Figma has no easing variable type).
  • #82 7d8d6b3 Thanks @tounsoo! - [Tokens] Add duration primitive tokens (0, 100, 200, 300, 400 ms) for motion timing. Each platform emits its idiomatic form: web emits a CSS <time> literal with the unit always present (100ms, and 0ms since CSS requires a unit on zero times), Swift emits seconds as a TimeInterval (100ms → 0.1, matching Animation(duration:)), and Kotlin emits raw milliseconds as an Int (100ms → 100, for Compose tween(durationMillis:))
  • #87 9b3dfa8 Thanks @tounsoo! - [Tokens] Add border.color.prominent semantic token (color.neutral.700) for the maximum-emphasis structural boundary on the single most critical bounded element in a view
  • #107 36c2afe Thanks @tounsoo! - [Tokens] Add scale semantic category — transform-scale intents for motion, expressing how far an element departs from its resting size (scale.1000 = 1.0). Six static number leaves named by moment: feedback (default press, {scale.950}), feedback-pronounced ({scale.900}), enter-quiet ({scale.800}), enter (default entrance, {scale.600}), enter-pronounced ({scale.500}), and exit ({scale.950}). Adds the supporting scale primitive scale (scale.100–scale.1000). Both tiers exclude the Figma platform, matching duration (no bindable scale/transform property in Figma).
  • #76 03a0e99 Thanks @tounsoo! - [Tokens] Add scrim semantic color token — a dim layer for blocking overlays (modal, drawer, dialog) that obscures and de-emphasizes content behind the foreground surface. Single static leaf scrim.color ({color.neutral.800} @ 0.6), dark mirrors light.
  • #65 1dd0874 Thanks @tounsoo! - [Tokens] Add tooltip.radius, tooltip.padding.inline, tooltip.padding.block, and a tooltip.font typography composite, and repoint tooltip.foreground / tooltip.background to the prominent semantic intents (foreground.color.on.prominent and background.color.prominent.resting) in place of raw color.neutral primitives. Tooltip now sources its surface (color, radius, padding) and typography from these tokens via the component proxy instead of hard-coded primitives, and renders its content in a plain <span> carrying tooltip.font rather than a nested <Text>.
  • #74 3935c98 Thanks @tounsoo! - [Tokens] Add userMessage and messageToolbar component tokens, and shift background.color.subtle (resting/hover/pressed) one neutral step darker

Patch Changes

  • #101 9c85f60 Thanks @tounsoo! - [Figma sync] Stop silently dropping new token types from validate/sync — only excludePlatforms: ["figma"] opts out; duration primitives explicitly figma-excluded.
  • #62 57c6646 Thanks @tounsoo! - [Tokens] Fix Compose shadow literal colors emitting unresolved Color(...) references — they now use ComposeColor to match the aliased import in the generated Kotlin file
  • #59 2b25a96 Thanks @tounsoo! - [Tokens] Fix color tokens with alpha < 1 dropping their transparency in the vanilla-extract output — they now emit rgba() instead of an opaque hex

0.1.1

Minor Changes

  • #31 69ef424 Thanks @tounsoo! - [Text, Tokens] Convert text tokens to DTCG typography composites; fix broken font-family in Swift build; Text now spreads composite values for font-family, weight, and line-height

Patch Changes

  • #40 63bee23 Thanks @tounsoo! - [Tokens] Sync DTCG $description to Figma variable descriptions
  • #43 9b77ac3 Thanks @tounsoo! - [Tokens] Fix composite shadow tokens emitting as [object Object] in Swift and Kotlin

0.1.0

Minor Changes

  • a3b08e5: [Tokens] Add components.icon.size.{small,medium,large,xlarge} tokens
  • 16bc697: [Text, Tokens] Add components.text.* tokens for headline / body / eyebrow variants
  • d0ec6be: [Tokens] Add Figma sync pipeline (figma:validate, figma:sync, figma:auth)
  • 0638cef: [Tokens] Add initial Style Dictionary pipeline for vanilla-extract, Swift, and Gradle
  • c676116: [Tokens] Restructure Swift and Kotlin exports to mirror source token paths (breaking for mobile consumers)
  • b6292cc: [Tokens] Add tooltip.foreground and tooltip.background color tokens
  • 48de98e: [Tokens] Align size and radius primitive scales to 100s notation (values unchanged)
  • 8178a7d: [Tokens] Add semantic token layer (background, foreground, border, radius, shadow, spacing, typography) with unified {ref, alpha} color shape
  • 1c2ea19: [Tokens] Singularize vanilla-extract tier names (primitives/components → primitive/component; deprecated aliases remain for one release)
  • 128f12e: [Tokens] Add font and stroke-style primitives, rebase radius to 4px steps, extend Figma sync coverage, and add preservePxForWeb extension
  • 974616f: [Tokens] Split vanilla-extract output into three tier-scoped createTheme layers with alias-preserving CSS variables (breaking: removed aggregate tokens export and single-call cartoThemeClass)

Patch Changes

  • 2578aea: [Tokens] Publish Android com.servicetitan:carto-tokens to Azure DevOps Maven feed on release
  • b6292cc: [Tokens] Conform tooltip and text component tokens to component-token authoring conventions
  • 5aa7870: [Tokens] Add GitHub Action for Figma sync (validate on PR, dry-run on main, manual sync with Slack notification)
  • 04c22a3: [Tokens] Make Figma variable scopes explicit at the group level for base, color, button, and background token files
  • 2e9073b: [Tokens] Fix Figma sync idempotency by normalizing FONT_STYLE ↔ FONT_WEIGHT in scope diff
Last modified on November 2, 2026