terrazzo-client 0.1.21

A simple macro to clone variables before passing them into a `move` closure or async block.
Documentation
# Terrazzo client

Template library to generate dynamic HTML documents.

The template library is usually used in tandem with the `terrazzo-macro` crate.

# The `#[html]` macro

## Basic usage
This macro us used to generate dynamic HTML nodes.

```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
#[html]
fn sample() -> XElement {
    div(
        h1("Section 1"),
        ul(li("Firstly"), li("Secondly")),
        h1("Section 2"),
        ol(li("One"), li("Two"), li("Three")),
    )
}
```

This function generates:
```html
<div>
    <h1> Section 1 </h1>
    <ul>
        <li> Firstly </li>
        <li> Secondly </li>
    </ul>
    <h1> Section 2 </h1>
    <ol>
        <li> One </li>
        <li> Two </li>
        <li> Three </li>
    </ol>
</div>
```

## List of nodes
List of nodes can be generated from iterators

```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
#[html]
fn sample() -> XElement {
    let list = [1, 2, 3].map(|i| li("{i}"));
    div(h1("Title"), ul(list..))
}
```

This function generates:
```html
<div>
    <h1> Title </h1>
    <ul>
        <li> 1 </li>
        <li> 2 </li>
        <li> 3 </li>
    </ul>
</div>
```

## Attributes
```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
#[html]
fn sample() -> XElement {
    div(
        class = "my-css-class",
        style = format!("width: {}%", 100),
        "Content",
    )
}
```

## Optional attributes
This can be useful when a function generates a node and an attribute may or may not have a value.
```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
#[html]
fn sample(class: Option<String>) -> XElement {
    div(
        class |= class,
        style = format!("width: {}%", 100),
        "Content",
    )
}
```

## Style properties
Style properties can be set individually.
```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
#[html]
fn sample(width: i32) -> XElement {
    div(
        style::width = format!("{}%", width),
        "Content",
    )
}
```

## Special attributes
`key`, `before-render` and `after-render` are special attributes.

See [XKey](crate::prelude::XKey) and [OnRenderCallback](crate::prelude::OnRenderCallback) for details.

# The `#[template]` macro

This macro can be used to create dynamic nodes.

## Simple case.
The tag and key have to be defined at the call site.
The node gets updated every time to `content` signal is updated.

```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
# use terrazzo_macro::template;
#[template]
#[html]
fn inner(name: String, #[signal] content: String) -> XElement {
    p("id={name}", "Content={content}")
}

#[html]
pub fn outer() -> XElement {
    let name = "Section 1".to_owned();
    let content = XSignal::new("content", "Hello, World!".to_owned());
    div(
        h1("Title"),
        p(key = name.clone(), move |t| {
            inner(t, name.clone(), content.clone())
        }),
    )
}
```

## With tag and key defined in the attribute

When the tag is defined on the attribute itself, the key should be defined on the `#[template]` attribute at well.

```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
# use terrazzo_macro::template;
#[template(tag = p, key = name.clone())]
#[html]
fn inner(name: String, #[signal] content: String) -> XElement {
    tag("id={name}", "Content={content}")
}

#[html]
pub fn outer() -> XElement {
    let name = "Section 1".to_owned();
    let content = XSignal::new("content", "Hello, World!".to_owned());
    div(h1("Title"), inner(name, content))
}
```

## Dynamic attributes
Attributes can be generated by signals that depend on dynamic signals.

Updating the signal will recompute and update the attribute or style property.

```
# use terrazzo_client::prelude::*;
# use terrazzo_macro::html;
# use terrazzo_macro::template;
#[html]
pub fn sample(suffix: XSignal<&'static str>, width: XSignal<i32>) -> XElement {
    div(
        class %= move |t| make_class(t, suffix.clone()),
        style::width %= move |t| make_width(t, width.clone()),
        "Content",
    )
}

#[template]
fn make_class(#[signal] suffix: &'static str) -> XAttributeValue {
    format!("class-{suffix}")
}

#[template]
fn make_width(#[signal] width: i32) -> XAttributeValue {
    format!("{}px", width)
}
```

# Debugging

## At runtime
The [tracing](https://docs.rs/tracing) crate is used to log events and add debugging information.

## At compile time
To debug code-generation, add `debug = true` to the `html` and `template` macros,
e.g.
- `#[html(debug = true)]`, and
- `#[template(debug = true)]`.