diff --git a/Cargo.lock b/Cargo.lock index 7fc2d0a3..856beb6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -613,6 +613,7 @@ dependencies = [ name = "counter" version = "0.1.0" dependencies = [ + "console_error_panic_hook", "wasm-bindgen", "web-sys", "xilem_html", @@ -622,6 +623,7 @@ dependencies = [ name = "counter_untyped" version = "0.1.0" dependencies = [ + "console_error_panic_hook", "wasm-bindgen", "web-sys", "xilem_html", @@ -3346,7 +3348,7 @@ dependencies = [ ] [[package]] -name = "xilemsvg" +name = "xilem_svg" version = "0.1.0" dependencies = [ "bitflags 1.3.2", diff --git a/crates/xilem_html/src/lib.rs b/crates/xilem_html/src/lib.rs index ca82a84f..2a984c8d 100644 --- a/crates/xilem_html/src/lib.rs +++ b/crates/xilem_html/src/lib.rs @@ -20,14 +20,14 @@ pub use xilem_core::MessageResult; pub use app::App; pub use class::class; -pub use context::ChangeFlags; +pub use context::{ChangeFlags, Cx}; #[cfg(feature = "typed")] pub use element::elements; pub use element::{element, Element, ElementState}; #[cfg(feature = "typed")] pub use event::events; pub use event::{on_event, Action, Event, OnEvent, OnEventState, OptionalAction}; -pub use view::{Adapt, AdaptThunk, Either, Pod, View, ViewMarker, ViewSequence}; +pub use view::{Adapt, AdaptThunk, AnyView, Either, Pod, View, ViewMarker, ViewSequence}; #[cfg(feature = "typed")] pub use view_ext::ViewExt; diff --git a/crates/xilem_html/src/view.rs b/crates/xilem_html/src/view.rs index f1df0684..bde5c076 100644 --- a/crates/xilem_html/src/view.rs +++ b/crates/xilem_html/src/view.rs @@ -126,8 +126,8 @@ where impl View for Either where - V1: View, - V2: View, + V1: View + ViewMarker, + V2: View + ViewMarker, V1::Element: AsRef + 'static, V2::Element: AsRef + 'static, { @@ -155,38 +155,36 @@ where state: &mut Self::State, element: &mut Self::Element, ) -> ChangeFlags { - let mut change_flags = ChangeFlags::empty(); match (prev, self) { (Either::Left(_), Either::Right(view)) => { let (new_id, new_state, new_element) = view.build(cx); *id = new_id; *state = Either::Right(new_state); *element = Either::Right(new_element); - change_flags |= ChangeFlags::STRUCTURE; + ChangeFlags::STRUCTURE } (Either::Right(_), Either::Left(view)) => { let (new_id, new_state, new_element) = view.build(cx); *id = new_id; *state = Either::Left(new_state); *element = Either::Left(new_element); - change_flags |= ChangeFlags::STRUCTURE; + ChangeFlags::STRUCTURE } (Either::Left(prev_view), Either::Left(view)) => { let (Either::Left(state), Either::Left(element)) = (state, element) else { throw_str("invalid state/view in Either (unreachable)"); }; // Cannot do mutable casting, so take ownership of state. - change_flags |= view.rebuild(cx, prev_view, id, state, element); + view.rebuild(cx, prev_view, id, state, element) } (Either::Right(prev_view), Either::Right(view)) => { let (Either::Right(state), Either::Right(element)) = (state, element) else { throw_str("invalid state/view in Either (unreachable)"); }; // Cannot do mutable casting, so take ownership of state. - change_flags |= view.rebuild(cx, prev_view, id, state, element); + view.rebuild(cx, prev_view, id, state, element) } } - change_flags } fn message( @@ -213,6 +211,94 @@ where } } +impl ViewSequence for Either +where + V1: ViewSequence, + V2: ViewSequence, +{ + type State = Either; + + fn build(&self, cx: &mut Cx, elements: &mut Vec) -> Self::State { + match self { + Either::Left(view_sequence) => Either::Left(view_sequence.build(cx, elements)), + Either::Right(view_sequence) => Either::Right(view_sequence.build(cx, elements)), + } + } + + fn rebuild( + &self, + cx: &mut Cx, + prev: &Self, + state: &mut Self::State, + element: &mut xilem_core::VecSplice, + ) -> ChangeFlags { + match (prev, self) { + (Either::Left(_), Either::Right(view_sequence)) => { + let new_state = element.as_vec(|elements| view_sequence.build(cx, elements)); + *state = Either::Right(new_state); + ChangeFlags::STRUCTURE + } + (Either::Right(_), Either::Left(view_sequence)) => { + let new_state = element.as_vec(|elements| view_sequence.build(cx, elements)); + *state = Either::Left(new_state); + ChangeFlags::STRUCTURE + } + (Either::Left(prev_view), Either::Left(view_sequence)) => { + let Either::Left(state) = state else { + throw_str("invalid state/view_sequence in Either (unreachable)"); + }; + view_sequence.rebuild(cx, prev_view, state, element) + } + (Either::Right(prev_view), Either::Right(view_sequence)) => { + let Either::Right(state) = state else { + throw_str("invalid state/view_sequence in Either (unreachable)"); + }; + view_sequence.rebuild(cx, prev_view, state, element) + } + } + } + + fn message( + &self, + id_path: &[xilem_core::Id], + state: &mut Self::State, + message: Box, + app_state: &mut T, + ) -> MessageResult { + match self { + Either::Left(view_sequence) => { + let Either::Left(state) = state else { + throw_str("invalid state/view_sequence in Either (unreachable)"); + }; + view_sequence.message(id_path, state, message, app_state) + } + Either::Right(view_sequence) => { + let Either::Right(state) = state else { + throw_str("invalid state/view_sequence in Either (unreachable)"); + }; + view_sequence.message(id_path, state, message, app_state) + } + } + } + + fn count(&self, state: &Self::State) -> usize { + match self { + Either::Left(view_sequence) => { + let Either::Left(state) = state else { + throw_str("invalid state/view_sequence in Either (unreachable)"); + }; + view_sequence.count(state) + } + Either::Right(view_sequence) => { + let Either::Right(state) = state else { + throw_str("invalid state/view_sequence in Either (unreachable)"); + }; + view_sequence.count(state) + } + } + } +} + // strings -> text nodes impl ViewMarker for &'static str {} diff --git a/crates/xilem_html/web_examples/counter/Cargo.toml b/crates/xilem_html/web_examples/counter/Cargo.toml index 548a7208..ad50a8ed 100644 --- a/crates/xilem_html/web_examples/counter/Cargo.toml +++ b/crates/xilem_html/web_examples/counter/Cargo.toml @@ -4,10 +4,8 @@ version = "0.1.0" license = "Apache-2.0" edition = "2021" -[lib] -crate-type = ["cdylib"] - [dependencies] +console_error_panic_hook = "0.1" wasm-bindgen = "0.2.87" web-sys = "0.3.64" xilem_html = { path = "../.." } diff --git a/crates/xilem_html/web_examples/counter/src/lib.rs b/crates/xilem_html/web_examples/counter/src/main.rs similarity index 91% rename from crates/xilem_html/web_examples/counter/src/lib.rs rename to crates/xilem_html/web_examples/counter/src/main.rs index 8dcb7f26..baf91904 100644 --- a/crates/xilem_html/web_examples/counter/src/lib.rs +++ b/crates/xilem_html/web_examples/counter/src/main.rs @@ -1,4 +1,3 @@ -use wasm_bindgen::{prelude::*, JsValue}; use xilem_html::{ document_body, elements as el, events::{self as evt}, @@ -64,11 +63,8 @@ fn app_logic(state: &mut AppState) -> impl View { )) } -// Called by our JS entry point to run the example -#[wasm_bindgen(start)] -pub fn run() -> Result<(), JsValue> { +pub fn main() { + console_error_panic_hook::set_once(); let app = App::new(AppState::default(), app_logic); app.run(&document_body()); - - Ok(()) } diff --git a/crates/xilem_html/web_examples/counter_untyped/Cargo.toml b/crates/xilem_html/web_examples/counter_untyped/Cargo.toml index 91659c49..978367bc 100644 --- a/crates/xilem_html/web_examples/counter_untyped/Cargo.toml +++ b/crates/xilem_html/web_examples/counter_untyped/Cargo.toml @@ -4,10 +4,8 @@ version = "0.1.0" license = "Apache-2.0" edition = "2021" -[lib] -crate-type = ["cdylib"] - [dependencies] +console_error_panic_hook = "0.1" wasm-bindgen = "0.2.87" web-sys = { version = "0.3.64", features = ["HtmlButtonElement"] } xilem_html = { path = "../..", default-features = false } diff --git a/crates/xilem_html/web_examples/counter_untyped/src/lib.rs b/crates/xilem_html/web_examples/counter_untyped/src/main.rs similarity index 88% rename from crates/xilem_html/web_examples/counter_untyped/src/lib.rs rename to crates/xilem_html/web_examples/counter_untyped/src/main.rs index 310639d7..9e78396d 100644 --- a/crates/xilem_html/web_examples/counter_untyped/src/lib.rs +++ b/crates/xilem_html/web_examples/counter_untyped/src/main.rs @@ -1,4 +1,3 @@ -use wasm_bindgen::{prelude::*, JsValue}; use xilem_html::{document_body, element, on_event, App, Event, View, ViewMarker}; #[derive(Default)] @@ -43,11 +42,8 @@ fn app_logic(state: &mut AppState) -> impl View { ) } -// Called by our JS entry point to run the example -#[wasm_bindgen(start)] -pub fn run() -> Result<(), JsValue> { +pub fn main() { + console_error_panic_hook::set_once(); let app = App::new(AppState::default(), app_logic); app.run(&document_body()); - - Ok(()) } diff --git a/crates/xilem_html/web_examples/todomvc/Cargo.toml b/crates/xilem_html/web_examples/todomvc/Cargo.toml index 04f072d5..6c0fb7c5 100644 --- a/crates/xilem_html/web_examples/todomvc/Cargo.toml +++ b/crates/xilem_html/web_examples/todomvc/Cargo.toml @@ -4,9 +4,6 @@ version = "0.1.0" license = "Apache-2.0" edition = "2021" -[lib] -crate-type = ["cdylib"] - [dependencies] console_error_panic_hook = "0.1.7" serde = { version = "1.0.170", features = ["derive"] } diff --git a/crates/xilem_html/web_examples/todomvc/src/lib.rs b/crates/xilem_html/web_examples/todomvc/src/main.rs similarity index 96% rename from crates/xilem_html/web_examples/todomvc/src/lib.rs rename to crates/xilem_html/web_examples/todomvc/src/main.rs index a5498b89..567d0585 100644 --- a/crates/xilem_html/web_examples/todomvc/src/lib.rs +++ b/crates/xilem_html/web_examples/todomvc/src/main.rs @@ -1,10 +1,7 @@ -use std::panic; - mod state; use state::{AppState, Filter, Todo}; -use wasm_bindgen::{prelude::*, JsValue}; use xilem_html::{ elements as el, events::on_click, get_element_by_id, Action, Adapt, App, MessageResult, View, ViewExt, ViewMarker, @@ -213,12 +210,8 @@ fn app_logic(state: &mut AppState) -> impl View { )) } -// Called by our JS entry point to run the example -#[wasm_bindgen(start)] -pub fn run() -> Result<(), JsValue> { - panic::set_hook(Box::new(console_error_panic_hook::hook)); +pub fn main() { + console_error_panic_hook::set_once(); tracing_wasm::set_as_global_default(); App::new(AppState::load(), app_logic).run(&get_element_by_id("todoapp")); - - Ok(()) } diff --git a/crates/xilem_html/web_examples/todomvc/src/state.rs b/crates/xilem_html/web_examples/todomvc/src/state.rs index 6d359a2c..98de0952 100644 --- a/crates/xilem_html/web_examples/todomvc/src/state.rs +++ b/crates/xilem_html/web_examples/todomvc/src/state.rs @@ -72,7 +72,7 @@ impl AppState { } pub fn start_editing(&mut self, id: u64) { - if let Some(ref mut todo) = self.todos.iter_mut().filter(|todo| todo.id == id).next() { + if let Some(ref mut todo) = self.todos.iter_mut().find(|todo| todo.id == id) { todo.title_editing.clear(); todo.title_editing.push_str(&todo.title); self.editing_id = Some(id) diff --git a/crates/xilem_svg/Cargo.toml b/crates/xilem_svg/Cargo.toml index cb17a12b..0666ea4d 100644 --- a/crates/xilem_svg/Cargo.toml +++ b/crates/xilem_svg/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "xilemsvg" +name = "xilem_svg" version = "0.1.0" license = "Apache-2.0" edition = "2021"