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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
//! # NeoView
//! NeoView is a lightweight, modern declarative UI framework that prioritizes robustness, safety, and efficiency over complex runtime magic.
//!
//! Aligned with Rust's core principles, NeoView offers a practical middle ground in declarative UI design. It supports ergonomic, fully reactive UI definitions with a strong emphasis on safety, robustness, efficiency, and renderer agnosticism.
//!
//! This crate provides the core components used by all renderers. For more information about a specific renderer, see its respective crate.
//!
//! # Reactive System
//! Inspired by SolidJS and Leptos, NeoView is powered by fine-grained reactivity. However, instead of relying on anonymous signals that carry heavy overhead, it utilizes a context-passing approach that satisfies the borrow checker while ensuring clear ownership and minimal overhead.
//!
//! Reactive states (also called properties) are stored in [`Store`]. These states are created by [`prop`](Store::prop) and accessed by ID ([`PropId`]) through methods like [`read`](Store::read), [`write`](Store::write), [`get`](Store::get), and [`update`](Store::update) on the [`Store`].
//! ```rust
//! let ctx = /* some `Context` */
//! let nb = ctx.prop(1);
//! assert_eq!(ctx.get(nb), 1);
//! ctx.write(nb, 2);
//! assert_eq!(ctx.get(nb), 2);
//! ```
//!
//! Reactive logic can be placed inside [`effect`s](Store::effect), and derived properties are created via [`computed`](Store::computed).
//! ```rust
//! let nb = ctx.prop(1);
//! ctx.effect(move |ctx| println!("nb: {}", ctx.get(nb)));
//! ctx.write(nb, 2); // => nb: 2
//! ```
//!
//! Any place that accesses state requires mutable access to a [`Context`], which is the type that owns the [`Store`], the UI, and everything related to it.
//!
//! [`Context`] and any type that provides access to the [`Store`] implement [`StoreProv`]ider, exposing the common methods of the [`Store`] directly.
//!
//! # Templating
//! NeoView utilizes a templating approach called chunked templating. The UI is constructed from multiple interleaved chunks, each chunk contains its own inlined logic and can host nested subchunks. This enables localized, nested UIs without requiring an excessive number of micro-components.
//!
//! The [`chunk`] macro allows writing UIs in a simple, expressive, object-like syntax.
//! ```rust
//! // using neoview-web
//! chunk!(build, div {
//! h1 { "counter" }
//! do {
//! let count = build.prop(0);
//! chunk!(build, button(
//! on.click: (move |ctx, _| ctx.update(count, |v| *v += 1))
//! ) { "count: ", count });
//! }
//! });
//! ```
//!
//! The UI is constructed at init time in an imperative style, and updates flow directly to specific elements using fine-grained reactivity.
//!
//! All Rust control flow and even all imperative patterns can be used inside chunks. There is no custom syntax for components, they are simply functions that borrow the context.
//!
//! ```rust
//! fn counter(build: &mut ChunkBuild, name: &str) {
//! let count = build.prop(0);
//! chunk!(build, button(
//! on.click: (move |ctx, _| ctx.update(count, |v| *v += 1))
//! ) { name, ": ", count });
//! }
//! fn main() {
//! // ...
//! chunk!(build, div {
//! for name in 'a'..'z' {
//! do { counter(build, name) }
//! br()
//! }
//! })
//! }
//! ```
//!
//! Note that the structure generated by these chunks is static rather than dynamic.
//!
//! # Renderers
//! NeoView is renderer-agnostic, it supports any platform or renderer, provided they implement the necessary items.
//!
//! It provides only the sharable parts between the renderers (the reactivity system and the chunk language) and also the philosophy, the unique rest is lift to the renderer.
//!
//! The available renderers include:
//! - [`neoview-web`](https://docs.rs/neoview_web/latest/neoview_web/): A renderer targeting the web platform based on HTML and the DOM.
/// Constructs a UI chunk in an expressive, object-like syntax.
///
/// `chunk` is a macro that defines and appends a UI chunk to the given chunk build using a universal, expressive syntax defined by the renderer.
///
/// `chunk` acts as a bridge. It parses a universal and raw element tree syntax into a series of [buildcodes](#buildcodes). These buildcodes are defined by the renderer, which further refines and restricts the syntax.
///
/// `chunk` allows the same expressive syntax to be universal across all renderers, however, each renderer has the right to interpret and refine the syntax according to its needs.
///
/// `chunk` is not the only way of templating, the renderer can provide additional templating methods.
///
/// # Example
/// ```
/// // using neoview-web
/// chunk!(build, div {
/// h1 { "counter" }
/// do {
/// let count = build.prop(0);
/// chunk!(build, button(
/// on.click: (move |ctx, _| ctx.update(count, |v| *v += 1))
/// ) { "count: ", count });
/// }
/// });
/// ```
///
/// ### Chunk Builds
/// Chunk builds are types that construct ui, they are passed to `chunk` macro and to the buildcodes, and are renderer defined.
///
/// They bahave like a tree builder not a linear one, chunks can be appended to them at any point inside the ui structure.
///
/// It is suggest to implement [`StoreProv`] or [`ScopedStoreProv`] for them to make them more ergonomic.
///
/// # Syntax
/// This section uses the [gramex meta language](https://docs.rs/gramex/latest/gramex/docs/gram_ref/index.html).
///
/// ### `chunk` Arguments
/// ```text
/// let chunk_args = (build = expr) "," children;
/// ```
/// The `chunk` macro takes two arguments: a `build` expression (whose type is defined by the renderer), and a list of children to be appended to the build at the target point.
///
/// ### Children
/// ```text
/// let children = (child_opt_comma | child_req_comma) (","? child_opt_comma | "," child_req_comma)* ","?;
/// let child_opt_comma = element | do_block | if_flow | for_flow | match_flow;
/// let child_req_comma = content;
/// ```
/// The chunk syntax represents a tree of element children, where children are items that can be nested inside an element.
///
/// A comma is used to separate children. Some items have it as optional ([elements](#element), [do blocks](#do-block)) and [control flows](#control-flows), while others require it ([contents](#content)). A trailing comma is allowed.
///
/// ```
/// chunk!(build,
/// el {} do {} "content", "other content", el {}
/// // same as:
/// el {}, do {}, "content", "other content", el {},
/// );
/// ```
///
/// ### Element
/// ```text
/// let element = (tag = path | str_lit) (attrs | body | attrs body);
/// let attrs = "(" list<ident | _+ ":" _+, ",">? ","? ")";
/// let body = "{" children? "}";
/// ```
/// An element is a UI element defined by a tag, and it can have attributes, children, or both.
///
/// A tag can be a [path](https://doc.rust-lang.org/reference/paths.html#simple-paths) or a string literal.
///
/// Attributes are a comma-separated list of `name: value` pairs enclosed inside parentheses (`()`), where the name and value can be any token list not containing a `,` or `:`.
///
/// A single identifier can be used as an attribute as a shorthand when both the name and the value are the same identifier.
///
/// The body is a curly brace (`{}`) block optionally containing children.
///
/// Tags, attribute names, and values are kept raw to support any renderer; the renderer will further restrict and refine them for its needs.
///
/// ```
/// chunk!(build,
/// el(attr1: value, attr2)
/// ns::el { "content", child {} }
/// "some-el"(ns.attr: (|a, b| a + b)) { "content" }
/// );
/// ```
///
/// ### Do Block
/// ```text
/// let do_block = "do" "{" _* "}";
/// ```
/// Do blocks are expression blocks defined after a `do` keyword that are evaluated when execution reaches where the block is defined inside the tree.
///
/// They are a unique feature to `neocomp` that allow inlining logic within the UI and separating the UI into multiple nested chunks.
///
/// ```
/// chunk!(build, div {
/// "after this",
/// do {
/// let count = build.prop(0);
/// chunk!(build, button(
/// on.click: (move |ctx, _| ctx.update(count, |v| *v += 1))
/// ) { "count: ", count });
/// chunk!(build, do {
/// chunk!("nested")
/// })
/// }
/// "before this",
/// });
/// ```
///
/// ### Control Flows
/// ```text
/// let if_flow = "if" expr "{" children "}" ("else" "if" expr "{" children "}")* ("else" "{" children "}")?;
/// let for_flow = "for" pat in expr "{" children "}";
/// let match_flow = "match" expr "{" (pat "=>" (child | "{" children "}") ","?)* "}";
/// ```
///
/// Control flows (`if`, `for`, and `match`) are operators that render their children conditionally or iteratively.
///
/// They are equivalent to their rust counterparts, except that their block is a children block.
///
/// They are static not dynamic or reactive, for the reactive versions see your renderer's documentation.
///
/// ```
/// chunk!(build, div {
/// if nb > 10 {
/// "greater than"
/// } else if nb < 10 {
/// "less than"
/// } else {
/// "equal"
/// }
///
/// for i in 0..10 {
/// "item: ", i, br()
/// }
///
/// match nb {
/// 0 => "zero",
/// 1 => span { "one" },
/// 2 => { "two" }
/// _ => "other"
/// }
/// });
/// ```
///
/// ### Content
/// ```text
/// let content = _+;
/// ```
/// Content is any token list that is not an element, a do block or a control flow.
///
/// It can be a string literal, an expression, or any other token list defined by the renderer.
///
/// ```
/// chunk!(build, "content", variable, 1 + 1, [1, 2, 3], move |ctx| ctx.get(prop));
/// ```
///
/// # Buildcodes
/// This section is meant for renderer maintainers.
///
/// The `chunk` macro transforms the element tree into a series of calls to buildcodes.
///
/// Buildcodes are macros defined inside a module named `__buildcode` within the caller's scope.
///
/// ### Chunk Buildcodes
/// ```
/// macro_rules! start_chunk {
/// ($build:expr) => { el:expr }
/// }
/// macro_rules! end_chunk {
/// ($build:expr, $el:expr) => {}
/// }
/// ```
///
/// The `chunk` macro starts by storing the `build` argument into a local variable so that it can be passed to all buildcodes.
///
/// Then, it calls `start_chunk` to adjust the build and returns the parent element of the top point.
///
/// Next, it calls the buildcodes of the top-level children.
///
/// Finally, it calls `end_chunk` with the parent element of the top point to end the chunk.
///
/// ### Element Buildcodes
/// ```
/// macro_rules! start_el {
/// ($build:expr, $el:expr, $($tag:tt)+) => { $el:expr };
/// }
/// macro_rules! attr {
/// ($build:expr, $el:expr, [$($name:tt)+], $($value:tt)+) => { };
/// }
/// macro_rules! end_el {
/// ($build:expr, $parent:expr, $el:expr, $($tag:tt)+) => { $el:expr };
/// }
/// ```
/// An element is transformed into a call to `start_el` with the tag tokens and the parent element to return the new element.
///
/// Then, attributes are transformed into calls to `attr` with the name tokens, value tokens, and the element.
///
/// Next, calls are made to the children's buildcodes.
///
/// Finally, a call to `end_el` is made with the parent element, the new element, and the tag tokens.
///
/// The element's type is left up to the renderer, and it can be `()` if not needed.
///
/// ### Content Buildcode
/// ```
/// macro_rules! content {
/// ($build:expr, $el:expr, $($content:tt)+) => { };
/// }
/// ```
/// `content` is called for every piece of content with the element and the content tokens.
///
/// ### Operators Buildcodes
/// ```
/// macro_rules! start_op {
/// ($build:expr, $op:ident, $el:expr) => { };
/// }
/// macro_rules! start_op {
/// ($build:expr, $op:ident, $el:expr) => { };
/// }
/// ```
/// `start_op` and `end_op` are called for every operator (do blocks and control flow) with the element.
///
/// An do block is transformed into an expression block containing a call to `start_op(do)`, followed by the block contents, and finally a call to `end_op(do)`.
///
/// A control flow is transformed into its rust equivalent, with the body containing a call to `start_op(op)`, followed by the children buildcodes, and finally a call to `end_op(op)`, where `op` is the name of the control flow.
///
/// ### Example
/// ```
/// chunk!(build, div {
/// span(id: "hello") { "world" }
/// do { println!("hello") }
/// for i in 0..10 { i }
/// });
///
/// // will be transformed into something like:
/// {
/// let mut build = build;
/// let mut el = __buildcode::start_chunk!(build);
/// let mut child = {
/// let mut el = __buildcode::start_el!(build, el, div);
/// let mut child = {
/// let el = __buildcode::start_el!(build, el, span);
/// __buildcode::attr!(build, el, [id], "hello");
/// __buildcode::content!(build, el, "world");
/// el
/// };
/// __buildcode::end_el!(build, el, child, span);
/// {
/// __buildcode::start_op!(build, do, el);
/// println!("hello");
/// __buildcode::end_op!(build, do el);
/// }
/// for i in 0..10 {
/// __buildcode::start_op!(build, for, el);
/// __buildcode::content!(build, el, i);
/// __buildcode::end_op!(build, for, el);
/// }
/// el
/// };
/// __buildcode::end_el!(build, el, child, div);
/// __buildcode::end_chunk!(build, el);
/// }
/// ```
pub use chunk;
pub use ;
/// an error raised by the reactivity system.