A simple web component system for Rust using web-dom for DOM access.
toml
webcomponent = "0.3"
Let's first create a component <hello-world>
that simply sets its inner HTML to "Hello World"
rust
pub struct HelloWorld {}
impl HelloWorld {
pub fn create(_custom_elements: &CustomElements, element: Element) {
element::set_inner_html(element, "Hello World!");
}
}
Now lets do some setup to register this custom element and setup a routing system for events from DOM
```rust
threadlocal! {
static CUSTOMELEMENTS:std::cell::RefCell
pub fn main() -> () { // This function starts listening for hello-world components CUSTOMELEMENTS.with(|c| { c.borrowmut().define("hello-world"); }); }
pub fn callback(callbackid: EventListener, event: Event) { // This function routes callbacks to the right closure CUSTOMELEMENTS.with(|c| { c.borrowmut().routecallback(callback_id, event); }); } ```
See it working here
In order to make a clock we'll need to be able to hold onto our component at a global level so it doesn't get deallocated.
```rust struct XClock { element: Element, }
impl XClock {
fn create(customelements: &mut CustomElements, element: Element) {
let x = XClock { element: element };
x.render();
let id = customelements.add(x);
let cb = createeventlistener();
window::setinterval(window(), cb, 1000);
customelements.addcallback(
cb,
Box::new(move |customelements, event| {
customelements.get::
fn timer(&self) {
self.render();
}
fn render(&self) {
let d = date::now_seconds();
let o = date::get_timezone_offset();
let now: DateTime<Utc> =
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp((d - (o * 60)) as i64, 0), Utc);
element::set_inner_html(self.element, &format!("{}", now.format("%I:%M:%S %p")));
}
} ```
See it working here
Let's take a look at an example that takes advantage of observing attribute changes and also a bit of shadow DOM.
```rust pub struct ColorText { element: Element, shadow: Element, }
impl ColorText { fn create(customelements: &mut CustomElements, element: Element) { let shadow = customelement::attachshadow(element); let id = custom_elements.add(ColorText { element: element, shadow: shadow, });
let mut cb = create_event_listener();
eventtarget::add_event_listener(element, "connected", cb);
custom_elements.add_callback(
cb,
Box::new(move |custom_elements, _| {
custom_elements.get::<ColorText>(id).connected();
}),
);
cb = create_event_listener();
eventtarget::add_event_listener(element, "attributechanged", cb);
custom_elements.add_callback(
cb,
Box::new(move |custom_elements, event| {
custom_elements
.get::<ColorText>(id)
.attribute_changed(event);
}),
);
}
fn connected(&self) {
self.render();
}
fn attribute_changed(&self, _event: Event) {
self.render();
}
fn render(&self) {
let c = element::get_attribute(self.element, "color");
element::set_inner_html(
self.shadow,
&format!(
"<style>:host {color:{} }</style><div><slot></slot></div>",
c
),
);
}
} ```
See it working here