Skip to main content

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}