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