Reference this PR.
nodes!
enum. This vec-like enum can be used to combine different collections of Node
s, for use in view macros. Example:nodes![
h1!["a node"],
vec![
h4["a vec"],
h4["of nodes"],
],
]
You can use native DOM elements safely because ElRef::get
checks if the referenced element exists, is in the DOM now, and has the right type. Check ouf the canvas
, user_media
, or todomvc
examples.
El::custom
added; this can be used to create an Element with a custom / arbitrary tag.
The two fundamental things to setup:
rustup update
from the cli: the project assumes a relatively new version of Rust.cargo install cargo-make
, a broadly useful tool to for Rust workflows.The two main steps:
cargo make start
- builds the project and serves it to localhost:8000.cargo make watch
is much like running start
, which is automatically re-run when a Rust file is changed.
The project Makefile has other useful commands, such as release builds.
Alternatively, create a new lib with Cargo: cargo new --lib appname
. Here and everywhere it appears in this guide, appname
should be replaced with the name of your app.
If not using the quickstart repo, create an Html file with a body that contains this:
<section id="app"></section>
<script type="module">
import init from '/pkg/package.js';
init('/pkg/package_bg.wasm');
</script>
The first line above is an empty element with id: It's where your app will render. The subsequent ones load your app's wasm modules.
The quickstart repo includes this file. You will eventually need to modify it to change the page's title, add a description, favicon, stylesheet etc.
Cargo.toml
, which is a file created by Cargo that describes your app, needs wasm-bindgen
, web-sys
, and seed
as dependencies, and crate-type of "cdylib"
. The version in the quickstart repo has these set up already. Example:
[package]
name = "appname"
version = "0.1.0"
authors = ["Your Name <email@address.com>"]
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
seed = "^0.6.0"
wasm-bindgen = "^0.2.50"
Here's an example demonstrating structure and syntax; it can be found in working form in the counter example. Descriptions of its parts are in the Guide section below. Its structure follows The Elm Architecture.
lib.rs:
use seed::{*, prelude::*};
// Model
struct Model {
count: i32,
what_we_count: String
}
// Setup a default here, for initialization later.
impl Default for Model {
fn default() -> Self {
Self {
count: 0,
what_we_count: "click".into()
}
}
}
// Update
#[derive(Clone)]
enum Msg {
Increment,
Decrement,
ChangeWWC(String),
}
/// How we update the model
fn update(msg: Msg, model: &mut Model, _orders: &mut impl Orders<Msg>) {
match msg {
Msg::Increment => model.count += 1,
Msg::Decrement => model.count -= 1,
Msg::ChangeWWC(what_we_count) => model.what_we_count = what_we_count,
}
}
// View
/// A simple component.
fn success_level(clicks: i32) -> Node<Msg> {
let descrip = match clicks {
0 ..= 5 => "Not very many 🙁",
6 ..= 9 => "I got my first real six-string 😐",
10 ..= 11 => "Spinal Tap 🙂",
_ => "Double pendulum 🙃"
};
p![ descrip ]
}
/// The top-level component we pass to the virtual dom.
fn view(model: &Model) -> impl View<Msg> {
let plural = if model.count == 1 {""} else {"s"};
// Attrs, Style, Events, and children may be defined separately.
let outer_style = style!{
St::Display => "flex";
St::FlexDirection => "column";
St::TextAlign => "center"
};
div![ outer_style,
h1![ "The Grand Total" ],
div![
style!{
// Example of conditional logic in a style.
St::Color => if model.count > 4 {"purple"} else {"gray"};
St::Border => "2px solid #004422";
St::Padding => unit!(20, px);
},
// We can use normal Rust code and comments in the view.
h3![ format!("{} {}{} so far", model.count, model.what_we_count, plural) ],
button![ simple_ev(Ev::Click, Msg::Increment), "+" ],
button![ simple_ev(Ev::Click, Msg::Decrement), "-" ],
// Optionally-displaying an element
if model.count >= 10 { h2![ style!{St::Padding => px(50)}, "Nice!" ] } else { empty![] }
],
success_level(model.count), // Incorporating a separate component
h3![ "What are we counting?" ],
input![ attrs!{At::Value => model.what_we_count}, input_ev(Ev::Input, Msg::ChangeWWC) ]
]
}
#[wasm_bindgen(start)]
pub fn render() {
App::builder(update, view)
.build_and_start();
}
For a truly minimal example, see lib.rs in the quickstart repo
To build your app, run cargo make build
, and to host on a dev server, run cargo make serve
.
For a more robust starting setup, check out Martin Kavik's seed-quickstart-webpack repo.
To run an example located in the examples folder, run cargo make start example_name
, where you replace example_name
with the example name. Eg: cargo make start counter
.
Some examples also require to run API server in another terminal window - cargo make start_server example_name
.
When server(s) are running, open 127.0.0.1:8000 in your browser.