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