1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! Tiny Maud superpowers.
//!
//! This crate is the public runtime/support surface:
//! - reexports proc macros like [`css!`] and [`js!`]
//! - optionally reexports the experimental [`Component`] derive
//! - optionally reexports the experimental [`component`] impl macro
//! - provides runtime slot wrapper types like [`Slot`] and [`Slots`]
//! - reexports `bon` so generated component code can depend only on
//! `maud-extensions`
//!
//! Recommended dependency spelling:
//!
//! ```toml
//! [dependencies]
//! mx = { package = "maud-extensions", version = "0.6.3", features = ["components"] }
//! ```
//!
//! # Experimental components
//!
//! The component system is currently opt-in behind the `components` feature.
//! The macro that turns impl-local component rendering and asset blocks on is:
//!
//! ```ignore
//! #[mx::component]
//! impl Card {
//! render! { ... }
//! css! { ... }
//! js!(once, { ... });
//! }
//! ```
//!
//! That impl macro is what makes `render!`, `css!`, and `js!` part of the
//! component render pipeline.
//!
//! The preferred authoring pattern is:
//!
//! - `#[derive(Component)]` on the struct
//! - `Slot<maud::Markup>` / `Slot<Vec<maud::Markup>>` for slot fields
//! - `#[mx(default)]` on the single default slot
//! - `#[mx::component]` on the inherent impl block
//! - `render! { ... }` for the component root
//! - optional colocated `css! { ... }` and `js!(once, { ... })` blocks
//!
//! The builder `.render()` path uses the hidden [`ComponentRender`] hook and
//! currently auto-injects impl-local CSS and JS into the rendered root.
//!
//! ```ignore
//! use maud::Markup;
//! use mx::{Component, Slot};
//!
//! #[derive(Component)]
//! struct Card {
//! title: String,
//! header: Slot<Markup>,
//! #[mx(default)]
//! body: Slot<Markup>,
//! footer: Slot<Markup>,
//! #[mx(each = action)]
//! actions: Slot<Vec<Markup>>,
//! }
//!
//! #[mx::component]
//! impl Card {
//! css! {
//! me {
//! padding: 1rem;
//! border: 1px solid #ddd;
//! }
//! }
//!
//! js!(once, {
//! me().class_add("ready");
//! });
//!
//! render! {
//! article.card {
//! header class="header" { (self.header) }
//! h2 { (self.title) }
//! div.body { (self.body) }
//! footer class="footer" { (self.footer) }
//! div.actions { (self.actions) }
//! }
//! }
//! }
//! ```
//!
//! The broader browser-side runtime pieces this layers on top of today include:
//!
//! - Surreal: <https://github.com/gnat/surreal>
//! - css-scope-inline: <https://github.com/gnat/css-scope-inline>
//! - Preact Signals: <https://github.com/preactjs/signals>
//!
//! To bootstrap those browser-side pieces in a page, emit one of the bundled
//! runtime macros in `<head>`:
//!
//! ```ignore
//! use maud::html;
//! use mx::surreal_scope_signals_inline;
//!
//! fn page() -> maud::Markup {
//! html! {
//! head { (surreal_scope_signals_inline!()) }
//! body { /* page body */ }
//! }
//! }
//! ```
extern crate self as maud_extensions;
pub use ;
pub use ;
pub use Component;
pub use component;
pub use bon;
/// Hidden render hook used by the component builder render path.