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