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
/*! HTML components for [consecuit].

This crate provides components like `div`, `span`, `table` for [consecuit].

## Basic usage

Also see the docs at [consecuit], as it also contain some info on how to use this.

First, import the prelude:

```
use consecuit_html::prelude::*;
```

Then you can use the components in the `cc_tree!` macro with the same structure as HTML:

```
cc_tree!(
    <div>
        <div>
        </div>
    </div>
    <span>"hello"</span>
)
```

## Props

All components in this crate takes props that can be built with builder pattern.

Start with [`html_props()`][elem::html_props()], then add your attributes.
Like this:

```
cc_tree!(
    <div {html_props().class_name("container container-box").onclick(click_handler)}>
    </div>
)
```

String attributes like `class_name` or `href` take anything that is `Into<Cow<'static, str>>`.
In the code above, `class_name` can take `"container container-box"` because it is `&'static str` which is `Into<Cow<'static, str>>`.

Event attributes like `onclick` or `oninput` take a [`Callback`][callback::Callback].
A [`Callback`][callback::Callback] can be created with `Callback::new`, like this:

```
let click_handler = Callback::new(move |ev: web_sys::MouseEvent| {
    web_sys::console::log_1(
        &"You clicked the button!".into()
    );
});

cc_tree!(
    <button {html_props().onclick(click_handler)}>"click me!"</button>
)
```


Sometimes you may get error about ambigous props.
For example, many different components take `href`.
The compiler won't allow this:

```
<a {html_props().href("https://example.com")}>"Go to web"</a>
```

You have to use [HtmlProps<(web_sys type of your element)>][elem::HtmlProps] instead. For example:

```
<a {HtmlProps::<web_sys::HtmlAnchorElement>::new().href("https://example.com")}>"Go to web"</a>
```


## Reference

To get a reference to the underlying [web_sys] element, you can use the `reference` prop.

The `reference` prop takes a [Reference][consecuit::hooks::Reference] of Option of the element type.
For instance, the input tag (`<input>`) has [web_sys::HtmlInputElement] as the underlying element.
So its reference must be a `Reference<Option<web_sys::HtmlInputElement>>`.

```
let (cc, input_ref): (_, Reference<Option<web_sys::HtmlInputElement>>) = cc.hook(use_ref, ());
cc_tree!(
    <input {html_props().reference(input_ref)} />
)
```

The Option inside the reference is guarunteed to be Some after the component rendered atleast once.

You can then use the methods in [Reference][consecuit::hooks::Reference] to do things with the underlying [web_sys] element.

For example, this read the value of an <input /> and set it to empty.
```
let (cc, input_ref): (_, Reference<Option<web_sys::HtmlInputElement>>) = cc.hook(use_ref, ());
let submit_click_handler = Callback::new(move |_ev| {
    let input_value = input_ref.visit_with(|opt: &Option<web_sys::HtmlInputElement>| {
        // Unwrap the Option<web_sys::HtmlInputElement>
        let inp: &web_sys::HtmlInputElement = opt.as_ref().unwrap();

        // Get the value
        let value = inp.value();

        // Set it to empty
        inp.set_value("");

        value
    }).unwrap();
    web_sys::console::log_1(&format!("The submitted value was: {}", input_value).into());
});

cc_tree!(
    <input {html_props().reference(input_ref)} />
    <button {html_props().onclick(submit_click_handler)}>"submit"</button>
)
```

## Notes

Most of the components and props in this crate are generated by a combination of parsing [web_sys]'s API and scraping MDN.

Only attributes with a `set_` method provided by [web_sys] are available as props.
For example, [web_sys] has `set_class_name`, so we have `class_name` prop.

Most notably missing is styling. [web_sys] does not have `set_style`. (it has a more sophisicated system for styling).
You have to stick with class names and CSS for now.

Contributions are welcome.

*/

pub mod callback;
pub mod components;
pub mod elem;
mod interfaces;
pub mod misc_components;
mod shared;

pub mod prelude {
    pub use crate::callback::Callback;
    pub use crate::components::*;
    pub use crate::elem::{html_props, HtmlProps};
    pub use crate::misc_components::*;
    pub use web_sys;
}