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