Define tokens and custom roles
Define semantic tokens
Section titled “Define semantic tokens”Theme::from_tokens creates a Theme and derives its canonical component
presentations. Use Theme::new when the application also supplies a complete
custom ComponentTheme.
The token fields are semantic inputs, not component-specific colors:
text ordinary content muted secondary content
accent selected action success completed
warning attention error failed
background cells surface panel
Add application roles
Section titled “Add application roles”Define role enums for meanings that belong to the application. Implement
TextThemeRole for inline text and BlockThemeRole for rectangles. Each role
receives the active Theme, so it continues to follow token overrides and
light/dark selection.
This complete example defines one role of each kind and renders both:
use std::io;
use urushi::{ Align, BlockStyle, BlockThemeRole, Border, Color, ComponentRole, SemanticTokens, TextStyle, TextThemeRole, Theme, View,};
#[derive(Clone, Copy)]enum AppTextRole { Command,}
impl TextThemeRole for AppTextRole { fn resolve(self, theme: &Theme) -> TextStyle { match self { Self::Command => theme .text_style(ComponentRole::Accent) .background(theme.tokens().surface) .bold(), } }}
#[derive(Clone, Copy)]enum AppBlockRole { Result,}
impl BlockThemeRole for AppBlockRole { fn resolve(self, theme: &Theme) -> BlockStyle { match self { Self::Result => BlockStyle::from_text_style( theme.text_style(ComponentRole::Success), ) .border(Border::ROUNDED) .border_foreground(theme.tokens().border) .padding((0, 1)), } }}
fn main() -> io::Result<()> { let theme = Theme::from_tokens(SemanticTokens { text: Color::BRIGHT_WHITE, text_muted: Color::BRIGHT_BLACK, background: Color::BLACK, surface: Color::BLACK, accent: Color::CYAN, accent_text: Color::BLACK, success: Color::GREEN, warning: Color::YELLOW, error: Color::RED, border: Color::BRIGHT_BLACK, });
let view = View::column( Align::Left, [ View::text("cargo test", theme.text_style(AppTextRole::Command)), View::block( theme.block_style(AppBlockRole::Result), View::text( "12 tests passed", theme.text_style(ComponentRole::Success), ), ), ], );
urushi::println_view(&view)}Rendered output
cargo test
╭─────────────────╮
│ 12 tests passed │
╰─────────────────╯
The command uses the theme’s accent and surface tokens. The result block uses the success and border tokens. Changing the selected Theme changes the concrete colors without changing either application role.
Derive custom roles from theme.tokens() or existing component roles so the
visual language remains connected. For one component instance, prefer cloning
and changing its presentation over constructing another Theme.