1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//! Compile-time CSS embedding via the [`css!`](crate::css) macro.
//!
//! The macro has two forms:
//!
//! - **File form** — `css!("theme.css")`: a CSS file is `include_str!`-ed into
//! the binary and lazily parsed into a
//! [`Stylesheet`](crate::Stylesheet). The path is relative to the source file
//! where the macro is invoked.
//! - **Inline form** — `css!(inline "Button { color: red; }")`: the CSS source
//! is an inline string literal, with no file involved. Handy for small
//! embedded themes that don't warrant a separate `.css` artifact.
//!
//! In both forms the parsed rules carry
//! [`Origin::Theme`](crate::Origin::Theme), so they can be overridden at
//! runtime by [`Origin::User`](crate::Origin::User) rules — see
//! [`RuntimeStyle`](crate::RuntimeStyle).
//!
//! The macro expands to a [`std::sync::LazyLock`] value, so it is meant to be
//! bound to a `static`. `LazyLock` derefs to `Stylesheet`, so you call methods
//! directly on the static; and because the data lives in the static, `&*THEME`
//! yields a `&'static Stylesheet` for APIs that need one (such as
//! [`RuntimeStyle::new`](crate::RuntimeStyle::new)).
//!
//! ```rust,ignore
//! use std::sync::LazyLock;
//! use ratatui_style::{css, OwnedNode, Stylesheet};
//!
//! static THEME: LazyLock<Stylesheet> = css!("theme.css");
//! // or, inline:
//! static THEME: LazyLock<Stylesheet> = css!(inline "Button { color: red; }");
//!
//! fn main() {
//! let node = OwnedNode::new("Button").with_classes(["primary"]);
//! let computed = THEME.compute(&node, None); // auto-deref through LazyLock
//! }
//! ```
//!
//! ## SCSS / Sass
//!
//! This crate deliberately does **not** depend on a Sass compiler. To embed
//! `.scss`, compile it to CSS in your own `build.rs` and point `css!` at the
//! generated file:
//!
//! ```rust,ignore
//! // Cargo.toml: [build-dependencies] grass = "0.13"
//! // build.rs:
//! // let css = grass::from_path("styles/theme.scss", &Default::default())?;
//! // std::fs::write(format!("{}/theme.css", OUT_DIR), css)?;
//!
//! use std::sync::LazyLock;
//! use ratatui_style::{css, Stylesheet};
//!
//! static THEME: LazyLock<Stylesheet> = css!(concat!(env!("OUT_DIR"), "/theme.css"));
//! ```
/// Embed CSS at compile time and lazily parse it into a
/// [`std::sync::LazyLock<Stylesheet>`](crate::Stylesheet).
///
/// Two forms:
///
/// - **File** — `css!("theme.css")`: the path is resolved relative to the
/// source file where the macro is invoked (via `include_str!`).
/// - **Inline** — `css!(inline "Button { color: red; }")`: the CSS source is an
/// inline string literal, with no file involved.
///
/// In both forms the parsed rules are tagged
/// [`Origin::Theme`](crate::Origin::Theme), making them overridable by
/// user-level rules at runtime (see [`RuntimeStyle`](crate::RuntimeStyle)).
///
/// Bind the result to a `static`; dereference (`&*THEME`) for a
/// `&'static Stylesheet`.
///
/// # Panics
///
/// Panics on first access if the CSS fails to parse. Since the CSS is fixed at
/// compile time, a parse error indicates a bug in the CSS source.