Tokens and themes
A token is a named value written as a CSS custom property. A theme sets its value for the whole page, and a style sets it for one element.
Tokens
Token::new(name, default) creates a token of a value type: Color, Length, Percentage, Time, or Angle. var() refers to the token as var(--name, default), so a page that sets no value uses the default. The result of var() can be passed anywhere a value of that type is accepted.
use hypersig::html::div;
use hypersig::style::value::{Color, px, rem};
use hypersig::style::{Media, Style, Theme, Token};
use hypersig::{Page, Signals};
use serde::{Deserialize, Serialize};
#[derive(Signals, Serialize, Deserialize)]
struct Board {
hue: String,
}
let surface = Token::new("surface", Color::hex(0x00ff_ffff));
let gap = Token::new("gap", rem(1));
let html = Page::new("Board", Board { hue: "#2563eb".into() })
// For the whole page, and under a media condition.
.theme(
Theme::new()
.set(&gap, rem(1.5))
.on(Media::Dark, Theme::new().set(&surface, Color::hex(0x0018_181b))),
)
.child(
div()
// Reading a token.
.css(Style::new().background_color(surface.var()).padding(gap.var()))
// For one element and those inside it.
.css(Style::new().token(&gap, px(8)))
// From a signal, unchecked like `bind_style`.
.bind_token(&surface, Board::hue()),
)
.render();
assert!(html.contains("var(--surface, #ffffff)"));Page::themetakes aTheme, whose values are written on:root.Theme::on(Media::Dark, ..)sets values under a media condition, and a laterthemecall adds to the earlier one.Style::tokensets a token on one element and those inside it, in place of the default and the page's theme.El::bind_tokenkeeps a token's value equal to the value of a string expression over the signals. As withEl::bind_style, the value is not checked.
The swatches and the button below read the same token. bind_token sets that token's value from the radio group's signal.
Result
accent.rs
use hypersig::html::div;
use hypersig::style::pattern::{stack, wrap};
use hypersig::style::value::{Color, px, rem};
use hypersig::style::{Style, Token};
use hypersig::{Page, Signals};
use hypersig_ui::{ButtonSize, ButtonVariant, button, radio_group, token};
use serde::{Deserialize, Serialize};
#[derive(Signals, Serialize, Deserialize)]
pub struct Palette {
accent: String,
}
pub fn page() -> Page<Palette> {
let accent = Token::new("accent-demo", Color::hex(0x0025_63eb));
let swatch = Style::new()
.width(rem(3))
.height(rem(3))
.border_radius(px(8))
.background_color(accent.var());
Page::new(
"Palette",
Palette {
accent: "#2563eb".into(),
},
)
.child(
div()
.css(stack(rem(1)))
.bind_token(&accent, Palette::accent())
.child(radio_group(
"Accent",
Palette::accent(),
[
(
"#2563eb".to_owned(),
"Blue",
),
(
"#16a34a".to_owned(),
"Green",
),
(
"#e11d48".to_owned(),
"Rose",
),
],
))
.child(
div()
.css(wrap(rem(0.75)))
.child(div().css(swatch.clone()))
.child(div().css(swatch.border_radius(px(999))))
.child(
button(ButtonVariant::Default, ButtonSize::Default)
// The button reads `primary`, which takes the accent here.
.css(Style::new().token(&token::primary(), accent.var()))
.text("Accent button"),
),
),
)
}