maciejhirsz / kobold

Easy declarative web interfaces.
https://docs.rs/kobold/
Mozilla Public License 2.0
385 stars 7 forks source link

Default parameters for components #67

Closed maciejhirsz closed 1 year ago

maciejhirsz commented 1 year ago

This PR allows for component parameters to have default values, showcased by the new default example:

use kobold::prelude::*;

#[component(
    // Make `name` an optional parameter, default to `"Kobold"`
    name?: "Kobold",
    // Make `age` an optional parameter, use the `Default` trait
    age?,
)]
fn Greeter<'a>(name: &'a str, age: u32) -> impl View + 'a {
    let age = (age > 0).then_some(view!(", you are "{ age }" years old"));

    view! {
        <p> "Hello "{ name }{ age }
    }
}

fn main() {
    kobold::start(view! {
        // Hello Kobold
        <Greeter />
        // Hello Alice
        <Greeter name="Alice" />
        // Hello Bob, you are 42 years old
        <Greeter name="Bob" age={42} />
    });
}

This is a breaking change when it comes to internals (the interaction between #[component] and view! macros), as components now set their fields using methods in a builder pattern. The user facing API remains unaffected, except type hints for component arguments now actually show useful information:

image

Rust compiler seems to handle this reasonably well as a zero-cost abstraction and doesn't increase the Wasm binary size (at least not in the TodoMVC example). With some fiddling we could make all the methods const if need be.

TODOs: