Add yew-autoprops to website documentation (#3505)

This commit is contained in:
Cecile Tonglet 2023-12-22 08:06:27 +01:00 committed by GitHub
parent 1d889347a6
commit b25703a035
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 162 additions and 80 deletions

27
Cargo.lock generated
View File

@ -1675,13 +1675,24 @@ dependencies = [
[[package]]
name = "implicit-clone"
version = "0.4.1"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af3d77000817fd9e7db159e8d52ed9b5941a2cdbfbdc8ca646e59887ae2b2dd1"
checksum = "fc06a255cbf402a52ae399c05a518c68c569c916ea11423620111df576b9b9bb"
dependencies = [
"implicit-clone-derive",
"indexmap 2.0.2",
]
[[package]]
name = "implicit-clone-derive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9311685eb9a34808bbb0608ad2fcab9ae216266beca5848613e95553ac914e3b"
dependencies = [
"quote",
"syn 2.0.38",
]
[[package]]
name = "indexmap"
version = "1.9.3"
@ -3615,6 +3626,7 @@ dependencies = [
"weblog",
"yew",
"yew-agent",
"yew-autoprops",
"yew-router",
]
@ -3876,6 +3888,17 @@ dependencies = [
"yew-agent",
]
[[package]]
name = "yew-autoprops"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58865a8f2470a6ad839274e05c9627170d32930f39a2348f8c425880a6131792"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]]
name = "yew-macro"
version = "0.21.0"

View File

@ -21,7 +21,7 @@ error[E0277]: the trait bound `Classes: From<{integer}>` is not satisfied
<Classes as From<&Option<T>>>
<Classes as From<&String>>
<Classes as From<&[T]>>
<Classes as From<&implicit_clone::unsync::IString>>
<Classes as From<&implicit_clone::unsync::string::IString>>
<Classes as From<Cow<'static, str>>>
<Classes as From<Option<T>>>
<Classes as From<String>>
@ -44,7 +44,7 @@ error[E0277]: the trait bound `Classes: From<{float}>` is not satisfied
<Classes as From<&Option<T>>>
<Classes as From<&String>>
<Classes as From<&[T]>>
<Classes as From<&implicit_clone::unsync::IString>>
<Classes as From<&implicit_clone::unsync::string::IString>>
<Classes as From<Cow<'static, str>>>
<Classes as From<Option<T>>>
<Classes as From<String>>
@ -67,7 +67,7 @@ error[E0277]: the trait bound `Classes: From<{integer}>` is not satisfied
<Classes as From<&Option<T>>>
<Classes as From<&String>>
<Classes as From<&[T]>>
<Classes as From<&implicit_clone::unsync::IString>>
<Classes as From<&implicit_clone::unsync::string::IString>>
<Classes as From<Cow<'static, str>>>
<Classes as From<Option<T>>>
<Classes as From<String>>
@ -93,7 +93,7 @@ error[E0277]: the trait bound `Classes: From<{integer}>` is not satisfied
<Classes as From<&Option<T>>>
<Classes as From<&String>>
<Classes as From<&[T]>>
<Classes as From<&implicit_clone::unsync::IString>>
<Classes as From<&implicit_clone::unsync::string::IString>>
<Classes as From<Cow<'static, str>>>
<Classes as From<Option<T>>>
<Classes as From<String>>
@ -119,7 +119,7 @@ error[E0277]: the trait bound `Classes: From<u32>` is not satisfied
<Classes as From<&Option<T>>>
<Classes as From<&String>>
<Classes as From<&[T]>>
<Classes as From<&implicit_clone::unsync::IString>>
<Classes as From<&implicit_clone::unsync::string::IString>>
<Classes as From<Cow<'static, str>>>
<Classes as From<Option<T>>>
<Classes as From<String>>
@ -145,7 +145,7 @@ error[E0277]: the trait bound `Classes: From<{integer}>` is not satisfied
<Classes as From<&Option<T>>>
<Classes as From<&String>>
<Classes as From<&[T]>>
<Classes as From<&implicit_clone::unsync::IString>>
<Classes as From<&implicit_clone::unsync::string::IString>>
<Classes as From<Cow<'static, str>>>
<Classes as From<Option<T>>>
<Classes as From<String>>

View File

@ -396,76 +396,76 @@ note: function defined here
| pub fn __ensure_type<T>(_: T) {}
| ^^^^^^^^^^^^^
error[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
error[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied
--> tests/html_macro/element-fail.rs:43:26
|
43 | html! { <input type={()} /> };
| ^^ the trait `IntoPropValue<Option<implicit_clone::unsync::IString>>` is not implemented for `()`
| ^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `()`
|
= help: the trait `IntoPropValue<VNode>` is implemented for `()`
error[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
error[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied
--> tests/html_macro/element-fail.rs:44:27
|
44 | html! { <input value={()} /> };
| ^^ the trait `IntoPropValue<Option<implicit_clone::unsync::IString>>` is not implemented for `()`
| ^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `()`
|
= help: the trait `IntoPropValue<VNode>` is implemented for `()`
error[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
error[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied
--> tests/html_macro/element-fail.rs:45:22
|
45 | html! { <a href={()} /> };
| ^^ the trait `IntoPropValue<Option<implicit_clone::unsync::IString>>` is not implemented for `()`
| ^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `()`
|
= help: the trait `IntoPropValue<VNode>` is implemented for `()`
error[E0277]: the trait bound `NotToString: IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
error[E0277]: the trait bound `NotToString: IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied
--> tests/html_macro/element-fail.rs:46:28
|
46 | html! { <input string={NotToString} /> };
| ^^^^^^^^^^^ the trait `IntoPropValue<Option<implicit_clone::unsync::IString>>` is not implemented for `NotToString`
| ^^^^^^^^^^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `NotToString`
|
= help: the following other types implement trait `IntoPropValue<T>`:
<&'static [(K, V)] as IntoPropValue<implicit_clone::unsync::IMap<K, V>>>
<&'static [T] as IntoPropValue<implicit_clone::unsync::IArray<T>>>
<&'static [(K, V)] as IntoPropValue<implicit_clone::unsync::map::IMap<K, V>>>
<&'static [T] as IntoPropValue<implicit_clone::unsync::array::IArray<T>>>
<&'static str as IntoPropValue<Classes>>
<&'static str as IntoPropValue<Option<String>>>
<&'static str as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<&'static str as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<&'static str as IntoPropValue<String>>
<&'static str as IntoPropValue<implicit_clone::unsync::IString>>
<&'static str as IntoPropValue<implicit_clone::unsync::string::IString>>
<&String as IntoPropValue<VNode>>
and $N others
error[E0277]: the trait bound `Option<NotToString>: IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
error[E0277]: the trait bound `Option<NotToString>: IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied
--> tests/html_macro/element-fail.rs:47:23
|
47 | html! { <a media={Some(NotToString)} /> };
| ^^^^ the trait `IntoPropValue<Option<implicit_clone::unsync::IString>>` is not implemented for `Option<NotToString>`
| ^^^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `Option<NotToString>`
|
= help: the following other types implement trait `IntoPropValue<T>`:
<Option<&'static str> as IntoPropValue<Option<String>>>
<Option<&'static str> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<Cow<'static, str>> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<&'static str> as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<Option<Cow<'static, str>> as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<Option<F> as IntoPropValue<Option<yew::Callback<I, O>>>>
<Option<Rc<str>> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<String> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<Rc<str>> as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<Option<String> as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<Option<VChild<T>> as IntoPropValue<Option<ChildrenRenderer<C>>>>
<Option<VNode> as IntoPropValue<VNode>>
error[E0277]: the trait bound `Option<{integer}>: IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
error[E0277]: the trait bound `Option<{integer}>: IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied
--> tests/html_macro/element-fail.rs:48:22
|
48 | html! { <a href={Some(5)} /> };
| ^^^^ the trait `IntoPropValue<Option<implicit_clone::unsync::IString>>` is not implemented for `Option<{integer}>`
| ^^^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `Option<{integer}>`
|
= help: the following other types implement trait `IntoPropValue<T>`:
<Option<&'static str> as IntoPropValue<Option<String>>>
<Option<&'static str> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<Cow<'static, str>> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<&'static str> as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<Option<Cow<'static, str>> as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<Option<F> as IntoPropValue<Option<yew::Callback<I, O>>>>
<Option<Rc<str>> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<String> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<Rc<str>> as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<Option<String> as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<Option<VChild<T>> as IntoPropValue<Option<ChildrenRenderer<C>>>>
<Option<VNode> as IntoPropValue<VNode>>
@ -567,11 +567,11 @@ error[E0277]: the trait bound `Option<yew::NodeRef>: IntoPropValue<yew::NodeRef>
|
= help: the following other types implement trait `IntoPropValue<T>`:
<Option<&'static str> as IntoPropValue<Option<String>>>
<Option<&'static str> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<Cow<'static, str>> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<&'static str> as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<Option<Cow<'static, str>> as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<Option<F> as IntoPropValue<Option<yew::Callback<I, O>>>>
<Option<Rc<str>> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<String> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<Rc<str>> as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<Option<String> as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<Option<VChild<T>> as IntoPropValue<Option<ChildrenRenderer<C>>>>
<Option<VNode> as IntoPropValue<VNode>>
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)
@ -603,20 +603,20 @@ note: required by a bound in `yew::html::onclick::Wrapper::__macro_new`
| |_^ required by this bound in `yew::html::onclick::Wrapper::__macro_new`
= note: this error originates in the macro `impl_action` which comes from the expansion of the macro `impl_short` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotToString: IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
error[E0277]: the trait bound `NotToString: IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied
--> tests/html_macro/element-fail.rs:60:28
|
60 | html! { <input string={NotToString} /> };
| ^^^^^^^^^^^ the trait `IntoPropValue<Option<implicit_clone::unsync::IString>>` is not implemented for `NotToString`
| ^^^^^^^^^^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `NotToString`
|
= help: the following other types implement trait `IntoPropValue<T>`:
<&'static [(K, V)] as IntoPropValue<implicit_clone::unsync::IMap<K, V>>>
<&'static [T] as IntoPropValue<implicit_clone::unsync::IArray<T>>>
<&'static [(K, V)] as IntoPropValue<implicit_clone::unsync::map::IMap<K, V>>>
<&'static [T] as IntoPropValue<implicit_clone::unsync::array::IArray<T>>>
<&'static str as IntoPropValue<Classes>>
<&'static str as IntoPropValue<Option<String>>>
<&'static str as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<&'static str as IntoPropValue<Option<implicit_clone::unsync::string::IString>>>
<&'static str as IntoPropValue<String>>
<&'static str as IntoPropValue<implicit_clone::unsync::IString>>
<&'static str as IntoPropValue<implicit_clone::unsync::string::IString>>
<&String as IntoPropValue<VNode>>
and $N others
@ -629,15 +629,16 @@ error[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied
= help: the trait `IntoPropValue<VNode>` is implemented for `()`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `implicit_clone::unsync::IString: From<{integer}>` is not satisfied
error[E0277]: the trait bound `implicit_clone::unsync::string::IString: From<{integer}>` is not satisfied
--> tests/html_macro/element-fail.rs:77:16
|
77 | html! { <@{55}></@> };
| ^^ the trait `From<{integer}>` is not implemented for `implicit_clone::unsync::IString`
| ^^ the trait `From<{integer}>` is not implemented for `implicit_clone::unsync::string::IString`
|
= help: the following other types implement trait `From<T>`:
<implicit_clone::unsync::IString as From<&'static str>>
<implicit_clone::unsync::IString as From<Cow<'static, str>>>
<implicit_clone::unsync::IString as From<Rc<str>>>
<implicit_clone::unsync::IString as From<String>>
= note: required because of the requirements on the impl of `Into<implicit_clone::unsync::IString>` for `{integer}`
<implicit_clone::unsync::string::IString as From<&'static str>>
<implicit_clone::unsync::string::IString as From<&implicit_clone::unsync::string::IString>>
<implicit_clone::unsync::string::IString as From<Cow<'static, str>>>
<implicit_clone::unsync::string::IString as From<Rc<str>>>
<implicit_clone::unsync::string::IString as From<String>>
= note: required because of the requirements on the impl of `Into<implicit_clone::unsync::string::IString>` for `{integer}`

View File

@ -27,7 +27,7 @@ yew-macro = { version = "^0.21.0", path = "../yew-macro" }
thiserror = "1.0"
futures = { version = "0.3", default-features = false, features = ["std"] }
html-escape = { version = "0.2.13", optional = true }
implicit-clone = { version = "0.4.1", features = ["map"] }
implicit-clone = { version = "0.4.8", features = ["map"] }
base64ct = { version = "1.6.0", features = ["std"], optional = true }
bincode = { version = "1.3.3", optional = true }
serde = { version = "1", features = ["derive"] }

View File

@ -17,6 +17,7 @@ wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
weblog = "0.3.0"
yew = { path = "../../packages/yew/", features = ["ssr", "csr"] }
yew-autoprops = "0.4.1"
yew-router = { path = "../../packages/yew-router/" }
tokio = { version = "1.33.0", features = ["rt", "macros"] }

View File

@ -60,14 +60,14 @@ pub struct Props {
}
#[function_component]
fn HelloWorld(props: &Props) -> Html {
html! { <>{"Am I loading? - "}{props.is_loading.clone()}</> }
fn HelloWorld(&Props { is_loading }: &Props) -> Html {
html! { <>{"Am I loading? - "}{is_loading}</> }
}
// Then supply the prop
#[function_component]
fn App() -> Html {
html! {<HelloWorld is_loading={true} />}
html! { <HelloWorld is_loading=true /> }
}
```
@ -126,8 +126,8 @@ pub struct Props {
}
#[function_component]
fn HelloWorld(props: &Props) -> Html {
if props.is_loading.clone() {
fn HelloWorld(&Props { is_loading }: &Props) -> Html {
if is_loading {
html! { "Loading" }
} else {
html! { "Hello world" }
@ -142,7 +142,7 @@ fn Case1() -> Html {
// Or no override the default
#[function_component]
fn Case2() -> Html {
html! {<HelloWorld is_loading={true} />}
html! { <HelloWorld is_loading=true /> }
}
```
@ -154,30 +154,36 @@ For example, to default a boolean prop to `true`, use the attribute `#[prop_or(t
is evaluated when the properties are constructed and no explicit value has been given.
```rust
use yew::{function_component, html, Html, Properties};
use yew::prelude::*;
#[derive(Properties, PartialEq)]
pub struct Props {
#[prop_or_default]
pub is_loading: bool,
// highlight-start
#[prop_or("Bob".to_string())]
#[prop_or(AttrValue::Static("Bob"))]
// highlight-end
pub name: String,
pub name: AttrValue,
}
#[function_component]
fn HelloWorld(props: &Props) -> Html {
html! {<>{"Hello world"}{props.name.clone()}</>}
fn Hello(&Props { is_loading, ref name }: &Props) -> Html {
if is_loading {
html! { "Loading" }
} else {
html! { <>{"Hello "}{name} </>}
}
}
// Then use like this with default
#[function_component]
fn Case1() -> Html {
html! {<HelloWorld />}
html! { <Hello /> }
}
// Or no override the default
#[function_component]
fn Case2() -> Html {
html! {<HelloWorld name={"Sam".to_string()} />}
html! { <Hello name="Sam" /> }
}
```
@ -188,34 +194,40 @@ Call `function` to initialize the prop value. `function` should have the signatu
The function is called when no explicit value has been given for that attribute.
```rust
use yew::{function_component, html, Html, Properties};
use yew::prelude::*;
fn create_default_name() -> String {
"Bob".to_string()
fn create_default_name() -> AttrValue {
AttrValue::Static("Bob")
}
#[derive(Properties, PartialEq)]
pub struct Props {
#[prop_or_default]
pub is_loading: bool,
// highlight-start
#[prop_or_else(create_default_name)]
// highlight-end
pub name: String,
pub name: AttrValue,
}
#[function_component]
fn HelloWorld(props: &Props) -> Html {
html! {<>{"Hello world"}{props.name.clone()}</>}
fn Hello(&Props { is_loading, ref name }: &Props) -> Html {
if is_loading {
html! { "Loading" }
} else {
html! { <>{"Hello "}{name}</> }
}
}
// Then use like this with default
#[function_component]
fn Case1() -> Html {
html! {<HelloWorld />}
html! { <Hello /> }
}
// Or no override the default
#[function_component]
fn Case2() -> Html {
html! {<HelloWorld name={"Sam".to_string()} />}
html! { <Hello name="Sam" /> }
}
```
@ -239,30 +251,70 @@ The macro uses the same syntax as a struct expression except that you can't use
The type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).
```rust
use yew::{function_component, html, Html, Properties, props, virtual_dom::AttrValue};
use yew::prelude::*;
#[derive(Properties, PartialEq)]
pub struct Props {
#[prop_or(AttrValue::from("Bob"))]
#[prop_or_default]
pub is_loading: bool,
#[prop_or(AttrValue::Static("Bob"))]
pub name: AttrValue,
}
#[function_component]
fn HelloWorld(props: &Props) -> Html {
html! {<>{"Hello world"}{props.name.clone()}</>}
fn Hello(&Props { is_loading, ref name }: &Props) -> Html {
if is_loading {
html! { "Loading" }
} else {
html! { <>{"Hello "}{name}</> }
}
}
#[function_component]
fn App() -> Html {
// highlight-start
let pre_made_props = props! {
let pre_made_props = yew::props! {
Props {} // Notice we did not need to specify name prop
};
// highlight-end
html! {<HelloWorld ..pre_made_props />}
html! { <Hello ..pre_made_props /> }
}
```
## Automatically generate properties (yew-autoprops)
In order to streamline your development process, you can also use the macro
`#[autoprops]` (from the crate `yew-autoprops`) that will automatically
generate the `Properties` struct for you.
```rust
use yew::prelude::*;
use yew_autoprops::autoprops;
// the #[autoprops] macro must appear BEFORE #[function_component], the order matters
#[autoprops]
#[function_component]
fn Greetings(
#[prop_or_default]
is_loading: bool,
#[prop_or(AttrValue::Static("Hello"))]
message: &AttrValue,
#[prop_or(AttrValue::Static("World"))]
name: &AttrValue,
) -> Html {
if is_loading {
html! { "Loading" }
} else {
html! { <>{message}{" "}{name}</> }
}
}
// The properties struct "GreetingsProps" will be generated automatically.
//
// `is_loading` will be passed as value to the components while `message` and
// `name` will use references because of the leading `&` in the definition.
```
## Evaluation Order
Props are evaluated in the order they're specified, as shown by the following example:
@ -296,7 +348,12 @@ These include, but are not limited to:
**Why is this bad?** Interior mutability (such as with `RefCell`, `Mutex`, etc.) should
_generally_ be avoided. It can cause problems with re-renders (Yew doesn't know when the state has changed)
so you may have to manually force a render. Like all things, it has its place. Use it with caution.
3. You tell us. Did you run into an edge-case you wish you knew about earlier? Feel free to create an issue
3. Using `Vec` type instead of `IArray`. <br />
**Why is this bad?** `Vec`, just like `String`, can also be expensive to clone. `IArray` is either
a reference-counted slice (`Rc<T>`) or a `&'static [T]`, thus very cheap to clone.<br />
**Note**: `IArray` can be imported from [implicit-clone](https://crates.io/crates/implicit-clone)
See that crate to learn more.
4. You tell us. Did you run into an edge-case you wish you knew about earlier? Feel free to create an issue
or PR a fix to this documentation.
## yew-autoprops