diff --git a/src/lib.rs b/src/lib.rs index fdb02ef..f966ab5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,19 +1,30 @@ use js_sys::Function; -use wasm_bindgen::JsValue; +use wasm_bindgen::{convert::IntoWasmAbi, prelude::*, JsCast, JsValue}; use web_sys::window; type Result = std::result::Result; -pub trait CustomElementImpl { +pub trait CustomElementImpl: IntoWasmAbi { fn class_name() -> &'static str; fn element_name() -> &'static str; + + fn construct() -> Self; } -pub fn define_web_component() -> Result { +pub struct WebComponentHandle { + pub impl_handle: Closure T>, + pub element_constructor: Function, +} + +pub fn define_web_component() -> Result> +where + T: CustomElementImpl + 'static, +{ let body = format!( "class {name} extends HTMLElement {{ constructor() {{ super(); + //this.impl = impl(); }} }} customElements.define(\"{element_name}\", {name}); @@ -22,17 +33,30 @@ return element;", name = T::class_name(), element_name = T::element_name(), ); - let fun = Function::new_no_args(&body); - Ok(fun.call0(&window().unwrap())?) + let fun = Function::new_with_args("impl", &body); + let f: Box T> = Box::new(|| T::construct()); + // TODO(jwall): Check the lifetimes on this guy. + let constructor_handle = Closure::wrap(f); + let element = fun + .call1( + &window().unwrap(), + constructor_handle.as_ref().unchecked_ref::(), + )? + .dyn_into()?; + Ok(WebComponentHandle { + element_constructor: element, + impl_handle: constructor_handle, + }) } #[cfg(test)] mod tests { use super::*; - use wasm_bindgen::{prelude::*, JsCast}; + use wasm_bindgen::JsCast; use wasm_bindgen_test::wasm_bindgen_test; wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + #[wasm_bindgen] pub struct MyElementImpl(); impl CustomElementImpl for MyElementImpl { @@ -43,6 +67,10 @@ mod tests { fn element_name() -> &'static str { "my-element" } + + fn construct() -> Self { + Self() + } } #[wasm_bindgen] @@ -56,7 +84,7 @@ mod tests { #[wasm_bindgen_test] fn test_component_definition() { let obj = define_web_component::().expect("Failed to define web component"); - let fun = obj.dyn_ref::().unwrap(); + let fun = obj.element_constructor.dyn_ref::().unwrap(); assert_eq!(fun.name(), MyElementImpl::class_name()); let element = window()