トークンとテーマ
トークンは CSS のカスタムプロパティとして書かれる名前付きの値です。テーマはページ全体に、スタイルは 1 つの要素にトークンの値を設定します。
トークン
Token::new(name, default) は、Color、Length、Percentage、Time、Angle のどれかの型のトークンを作ります。var() はトークンを var(--name, default) の形で参照するので、値を何も設定しないページでは既定値が使われます。var() の結果はその型の値を受け取る場所ならどこにでも渡せます。
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::themeはThemeを受け取り、その値を:rootに書きます。Theme::on(Media::Dark, ..)はメディアの条件の下で値を設定します。themeを後からもう一度呼ぶと、前の呼び出しの値に足されます。Style::tokenは 1 つの要素とその内側の要素にトークンを設定し、既定値とページのテーマの値を置き換えます。El::bind_tokenは、トークンの値をシグナルから作る文字列の式の値と常に同じにします。El::bind_styleと同じく、値は検査しません。
下の色見本とボタンは同じトークンを読みます。このトークンの値は、bind_token がラジオグループのシグナルから設定します。
実行結果
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 {
accent: "#2563eb".into(),
},
)
.child(
div()
.css(stack(rem(1)))
.bind_token(&accent, Palette::accent())
.child(radio_group(
"アクセント",
Palette::accent(),
[
(
"#2563eb".to_owned(),
"青",
),
(
"#16a34a".to_owned(),
"緑",
),
(
"#e11d48".to_owned(),
"ローズ",
),
],
))
.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("アクセントのボタン"),
),
),
)
}