Skip to main content

euv_macros/
lib.rs

1//! euv_macros
2//!
3//! Procedural macros for the euv UI framework, including the `html!` macro
4//! for declarative UI syntax, the `class!` macro for CSS class definitions,
5//! the `css_vars!` macro for CSS custom properties, the `watch!` macro for
6//! reactive side effects, and the `component` attribute macro.
7
8mod class;
9mod css_vars;
10mod html;
11mod kebab;
12mod var;
13mod watch;
14
15pub(crate) use {class::*, css_vars::*, html::*, kebab::*, watch::*};
16
17use std::iter::Peekable;
18
19use {
20    lombok_macros::*,
21    proc_macro::TokenStream,
22    proc_macro2::Span,
23    quote::{ToTokens, quote, quote_spanned},
24    syn::{
25        Expr, ExprLit, Ident, Lit, LitStr, Path, Token, Type, Visibility, braced, parenthesized,
26        parse,
27        parse::{Parse, ParseBuffer, ParseStream},
28        parse2,
29        token::{Brace, Colon, Paren, Semi},
30    },
31};
32
33/// The `html!` macro for writing declarative UI in euv.
34///
35/// This macro accepts a syntax similar to Dioxus HTML:
36///
37/// ```ignore
38/// html! {
39///     div {
40///         class: c_container()
41///         h1 { "Hello, euv!" }
42///         button {
43///             onclick: move |_| { /* handle click */ },
44///             "Click me"
45///         }
46///     }
47/// }
48/// ```
49#[proc_macro]
50pub fn html(input: TokenStream) -> TokenStream {
51    html::parse_html(input)
52}
53
54/// The `class!` macro for defining CSS classes with style properties.
55///
56/// Each class definition creates a `CssClass` function that can be used
57/// in `html!` via the `class:` attribute. Styles are automatically injected
58/// into the DOM on first use.
59///
60/// ```ignore
61/// class! {
62///     pub container {
63///         max_width: "800px";
64///         margin: "0 auto";
65///     }
66///     pub(crate) header {
67///         font_size: "28px";
68///     }
69///     hidden {
70///         display: "none";
71///     }
72/// }
73/// ```
74#[proc_macro]
75pub fn class(input: TokenStream) -> TokenStream {
76    class::parse_class(input)
77}
78
79/// The `watch!` macro for creating reactive side effects.
80///
81/// Watches one or more signals and executes a closure whenever any of them changes.
82/// The closure is also executed once immediately with the current signal values
83/// during initialisation. This initial execution is wrapped in a suppressed-update
84/// scope so that any `.set()` calls inside the body do not trigger unnecessary
85/// DynamicNode re-renders.
86///
87/// The number of signal expressions must match the number of closure parameters.
88/// Each closure parameter receives the current value (via `.get()`) of the
89/// corresponding signal.
90///
91/// ```ignore
92/// let count = use_signal(|| 0_i32);
93/// let name = use_signal(|| String::from("euv"));
94/// watch!(count, name, |count_val, name_val| {
95///     web_sys::console::log_1(&format!("count={}, name={}", count_val, name_val).into());
96/// });
97/// ```
98#[proc_macro]
99pub fn watch(input: TokenStream) -> TokenStream {
100    watch::parse_watch(input)
101}
102
103/// The `css_vars!` macro for defining CSS custom properties.
104///
105/// Each variable block creates a `CssClass` function that, when called,
106/// injects the CSS custom properties into the DOM. Variable names are
107/// automatically prefixed with `--`.
108///
109/// Variable names can be written as unquoted kebab-case identifiers
110/// (e.g., `bg-primary`) or as quoted string literals (e.g., `"bg-primary"`).
111///
112/// ```ignore
113/// css_vars! {
114///     pub c_theme_light {
115///         bg-primary: "#f8f9fb";
116///         text-primary: "#1a1a2e";
117///     }
118/// }
119/// ```
120#[proc_macro]
121pub fn css_vars(input: TokenStream) -> TokenStream {
122    css_vars::parse_css_vars(input)
123}
124
125/// The `var!` macro for referencing CSS custom properties defined via `css_vars!`.
126///
127/// The variable name can be written as an unquoted kebab-case identifier
128/// (e.g., `bg-primary`) or as a quoted string literal (e.g., `"bg-primary"`),
129/// and expands to the CSS string `"var(--bg-primary)"`.
130///
131/// ```ignore
132/// css_vars! {
133///     pub c_theme {
134///         bg-primary: "#f8f9fb";
135///     }
136/// }
137/// class! {
138///     pub c_container {
139///         background: var!(bg-primary);
140///     }
141/// }
142/// ```
143#[proc_macro]
144pub fn var(input: TokenStream) -> TokenStream {
145    var::parse_var(input)
146}
147
148/// The `component` attribute macro for marking component functions.
149///
150/// This is a pass-through attribute macro that does not modify the item.
151/// It serves as a marker to indicate that the annotated function is a
152/// UI component that returns a `VirtualNode`.
153///
154/// # Arguments
155///
156/// - `TokenStream` - The attribute arguments (unused).
157/// - `TokenStream` - The item being annotated (passed through unchanged).
158///
159/// # Returns
160///
161/// - `TokenStream` - The original item unchanged.
162#[proc_macro_attribute]
163pub fn component(_attr: TokenStream, item: TokenStream) -> TokenStream {
164    item
165}