# Asteracea
[![Lib.rs](https://img.shields.io/badge/Lib.rs-*-84f)](https://lib.rs/crates/asteracea)
[![Crates.io](https://img.shields.io/crates/v/asteracea)](https://crates.io/crates/asteracea)
[![Docs.rs](https://docs.rs/asteracea/badge.svg)](https://docs.rs/crates/asteracea)
![Rust 1.45.0](https://img.shields.io/static/v1?logo=Rust&label=&message=1.45.0&color=grey)
[![Build Status](https://travis-ci.com/Tamschi/Asteracea.svg?branch=unstable)](https://travis-ci.com/Tamschi/Asteracea/branches)
![Crates.io - License](https://img.shields.io/crates/l/asteracea/0.0.2)
[![GitHub](https://img.shields.io/static/v1?logo=GitHub&label=&message=%20&color=grey)](https://github.com/Tamschi/Asteracea)
[![open issues](https://img.shields.io/github/issues-raw/Tamschi/Asteracea)](https://github.com/Tamschi/Asteracea/issues)
[![open pull requests](https://img.shields.io/github/issues-pr-raw/Tamschi/Asteracea)](https://github.com/Tamschi/Asteracea/pulls)
[![crev reviews](https://web.crev.dev/rust-reviews/badge/crev_count/asteracea.svg)](https://web.crev.dev/rust-reviews/crate/asteracea/)
Asteracea is a web application framework aiming to combine the strengths of [Angular] and [React] while fully supporting Rust's lifetime model.
[Angular]: https://angular.io/
[React]: https://reactjs.org/
**Note: Asteracea is experimental software.**
While it appears to work well so far, there likely will be breaking changes to the template syntax.
## Installation
Please use [cargo-edit](https://crates.io/crates/cargo-edit) to always add the latest version of this library:
```cmd
cargo add asteracea
```
## Design goals
* Little boilerplate / Useful defaults
Most generated boilerplate code is adjusted automatically to what is required. For example, the signature of a component's `.render` method changes if a `Node` is generated.
[There is still room for improvement here without sacrificing readability.](https://github.com/Tamschi/Asteracea/projects/2)
* Co-location / [DRY]
Intent shouldn't need to be reiterated in multiple places (split declaration, initialisation and usage).
For now, short form captures nested in the component templates provide a way to centralise some semantics (similarly to React's Hooks but without their control flow limitations).
[Further improvements in this area are planned.](https://github.com/Tamschi/Asteracea/projects/1)
[DRY]: https://en.wikipedia.org/w/index.php?title=Don%27t_repeat_yourself&oldid=972595923
* Robust code
Element names are statically checked against [`lignin-schema`] by default, but other schemata can be defined similarly. Empty elements like ` ` cannot contain children.
Similar checks for attributes and event names are planned.
[`lignin-schema`]: https://github.com/Tamschi/lignin-schema
* No default runtime
Asteracea components compile to plain Rust code with (usually) no further dependencies, which helps keep bundles small.
Use [`lignin-dom`] or [`lignin-html`] to transform rendered `Node` trees into live user interfaces.
[`lignin-dom`]: https://github.com/Tamschi/lignin-dom
[`lignin-html`]: https://github.com/Tamschi/lignin-html
## Examples
### Empty component
The most simple (`Node`-rendering) component can be written like this:
```rust
asteracea::component! {
Empty()()
[] // Empty node sequence
}
// Render into a bump allocator:
let mut bump = lignin::bumpalo::Bump::new();
assert!(matches!(
Empty::new().render(&mut bump),
lignin::Node::Multi(&[]) // Empty node sequence
));
```
### Unit component
If the component body isn't a `Node` expression, the component will return `()` by default and won't require a `Bump` reference to be rendered.
A different return type can be specified after the render argument list.
```rust
asteracea::component! {
Unit(/* ::new arguments */)(/* .render arguments */) /* -> () */
{} // Empty Rust block
}
asteracea::component! {
Offset(base: usize)(offset: usize) -> usize
|pub base: usize = {base}|; // ²
{ self.base + offset }
}
assert_eq!(Unit::new().render(), ());
assert_eq!(Offset::new(2).render(3), 5);
```
²
### Counter component
For a relatively complex example, see this parametrised counter:
```rust
use asteracea::component;
use std::cell::RefCell;
fn schedule_render() { /* ... */ }
component! {
pub Counter(initial: i32, step: i32)()
|value = RefCell::::new(initial)|; // shorthand capture
|step: i32 = {step}|; // long form capture, ²