1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
use crate::dom::{MountAction, MountTarget};
use crate::wasm_bindgen;
use crate::{Application, Program};
use wasm_bindgen::JsValue;
#[wasm_bindgen(module = "/js/define_custom_element.js")]
extern "C" {
// register using custom element define
// # Example:
// ```rust,ignore
// sauron::register_custom_element("date-time", "DateTimeWidgetCustomElement");
// ```
pub fn register_custom_element(custom_tag: &str, adapter: &str);
}
/// a trait for implementing CustomElement in the DOM with custom tag
pub trait CustomElement<MSG> {
/// the custom tag that this custom element will be registerd to the browser
fn custom_tag() -> &'static str;
/// returns the attributes that is observed by this component
/// These are the names of the attributes the component is interested in
fn observed_attributes() -> Vec<&'static str>;
/// This will be invoked when a component is used as a custom element
/// and the attributes of the custom-element has been modified
///
/// if the listed attributes in the observed attributes are modified
fn attribute_changed<APP>(
program: &Program<APP, MSG>,
attr_name: &str,
old_value: JsValue,
new_value: JsValue,
) where
APP: Application<MSG> + 'static,
MSG: 'static;
/// the component is attached to the dom
fn connected_callback(&mut self);
/// the component is removed from the DOM
fn disconnected_callback(&mut self);
/// the component is moved or attached to the dom
fn adopted_callback(&mut self);
}
/// A self contain web component
/// This is needed to move some of the code from the #web_component macro
/// This is also necessary, since #[wasm_bindgen] macro can not process impl types which uses
/// generics, we use generics here to simplify the code and do the type checks for us, rather than
/// in the code derived from the #[web_component] macro
pub struct WebComponent<APP, MSG>
where
MSG: 'static,
{
program: Program<APP, MSG>,
}
impl<APP, MSG> WebComponent<APP, MSG>
where
APP: Application<MSG> + Default + 'static,
APP: CustomElement<MSG>,
MSG: 'static,
{
/// create a new web component, with the node as the target element to be mounted into
pub fn new(node: JsValue) -> Self {
use crate::wasm_bindgen::JsCast;
let mount_node: &web_sys::Node = node.unchecked_ref();
Self {
program: Program::new(
APP::default(),
mount_node,
MountAction::Append,
MountTarget::ShadowRoot,
),
}
}
/// When the attribute of the component is changed, this method will be called
pub fn attribute_changed(&self, attr_name: &str, old_value: JsValue, new_value: JsValue) {
APP::attribute_changed(&self.program, attr_name, old_value, new_value)
}
/// called when the web component is mounted
pub fn connected_callback(&mut self) {
self.program.mount();
let component_style = <APP as Application<MSG>>::style(&self.program.app.borrow());
self.program.inject_style_to_mount(&component_style);
self.program.update_dom().expect("must update dom");
self.program.app.borrow_mut().connected_callback();
}
/// called when the web component is removed
pub fn disconnected_callback(&mut self) {
self.program.app.borrow_mut().disconnected_callback();
}
/// called when web componented is moved into other parts of the document
pub fn adopted_callback(&mut self) {
self.program.app.borrow_mut().adopted_callback();
}
}