hypersig_ui/token.rs
1//! The design tokens the components read their colors and radius from.
2//!
3//! The names and the light values follow shadcn/ui's zinc theme. The values
4//! differ where shadcn/ui falls short of WCAG 2.2 AA: [`input`] is dark
5//! enough for the 3:1 contrast that a control's boundary needs (1.4.11),
6//! [`muted_foreground`] keeps 4.5:1 on [`muted`] as well as on
7//! [`background`], and [`ring`] is drawn as a solid outline rather than a
8//! translucent shadow (2.4.7).
9//!
10//! Set a token for a whole page with a [`Theme`](hypersig::style::Theme), or
11//! for one element with [`Style::token`](hypersig::style::Style::token).
12//!
13//! ```
14//! use hypersig::style::Theme;
15//! use hypersig::style::value::Color;
16//! use hypersig_ui::token;
17//!
18//! let brand = Theme::new().set(&token::primary(), Color::hex(0x0025_63eb));
19//! assert!(brand.to_css().contains("--primary:#2563eb"));
20//! ```
21
22use hypersig::style::Token;
23use hypersig::style::value::{Color, Length, rem};
24
25macro_rules! colors {
26 ($($(#[$doc:meta])* $name:ident => $css:literal, $light:literal, $dark:literal;)*) => {
27 $(
28 $(#[$doc])*
29 #[must_use]
30 pub fn $name() -> Token<Color> {
31 Token::new($css, Color::hex($light))
32 }
33 )*
34
35 /// Each color token with its value in the light theme.
36 pub(crate) fn light() -> Vec<(Token<Color>, Color)> {
37 vec![$(($name(), Color::hex($light))),*]
38 }
39
40 /// Each color token with its value in the dark theme.
41 pub(crate) fn dark() -> Vec<(Token<Color>, Color)> {
42 vec![$(($name(), Color::hex($dark))),*]
43 }
44 };
45}
46
47colors! {
48 /// The page background.
49 background => "background", 0x00ff_ffff, 0x0009_090b;
50 /// Text on [`background`].
51 foreground => "foreground", 0x0009_090b, 0x00fa_fafa;
52 /// The surface of a card.
53 card => "card", 0x00ff_ffff, 0x0018_181b;
54 /// Text on [`card`].
55 card_foreground => "card-foreground", 0x0009_090b, 0x00fa_fafa;
56 /// The surface of a menu or another popover.
57 popover => "popover", 0x00ff_ffff, 0x0018_181b;
58 /// Text on [`popover`].
59 popover_foreground => "popover-foreground", 0x0009_090b, 0x00fa_fafa;
60 /// The fill of a default button, a checked box, and an on switch.
61 primary => "primary", 0x0018_181b, 0x00e4_e4e7;
62 /// Text and marks on [`primary`].
63 primary_foreground => "primary-foreground", 0x00fa_fafa, 0x0018_181b;
64 /// The fill of a secondary button.
65 secondary => "secondary", 0x00f4_f4f5, 0x0027_272a;
66 /// Text on [`secondary`].
67 secondary_foreground => "secondary-foreground", 0x0018_181b, 0x00fa_fafa;
68 /// A quiet fill, such as the track of a tab list.
69 muted => "muted", 0x00f4_f4f5, 0x0027_272a;
70 /// Secondary text, such as a description, at 4.8:1 or more on
71 /// [`background`] and on [`muted`] in both themes.
72 muted_foreground => "muted-foreground", 0x006b_6b74, 0x00a1_a1aa;
73 /// The fill under the pointer in a menu or a ghost button.
74 accent => "accent", 0x00f4_f4f5, 0x003f_3f46;
75 /// Text on [`accent`].
76 accent_foreground => "accent-foreground", 0x0018_181b, 0x00fa_fafa;
77 /// The color of a destructive action and of an error message.
78 destructive => "destructive", 0x00e7_000b, 0x00ff_6467;
79 /// Text on [`destructive`].
80 destructive_foreground => "destructive-foreground", 0x00ff_ffff, 0x0009_090b;
81 /// The border of a card, a menu, and a separator, which mark no control.
82 border => "border", 0x00e4_e4e7, 0x0027_272a;
83 /// The border of a text field, a checkbox, a radio, and an off switch,
84 /// at 3.3:1 or more on [`background`] and on [`card`] in both themes.
85 input => "input", 0x008b_8b94, 0x0070_707a;
86 /// The focus outline.
87 ring => "ring", 0x0018_181b, 0x00d4_d4d8;
88 /// The first series of a chart. The five chart colors keep 3:1 or more
89 /// on [`background`], [`card`], and [`muted`] in both themes.
90 chart_1 => "chart-1", 0x0015_5dfc, 0x0051_a2ff;
91 /// The second series of a chart.
92 chart_2 => "chart-2", 0x0000_9689, 0x0000_d5be;
93 /// The third series of a chart.
94 chart_3 => "chart-3", 0x00f5_4900, 0x00ff_8904;
95 /// The fourth series of a chart.
96 chart_4 => "chart-4", 0x0098_10fa, 0x00c2_7aff;
97 /// The fifth series of a chart.
98 chart_5 => "chart-5", 0x00bb_4d00, 0x00ff_d230;
99}
100
101/// The corner radius of a card, a dialog, and a menu.
102#[must_use]
103pub fn radius() -> Token<Length> {
104 Token::new("radius", rem(0.625))
105}