webcomponent

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 = std::cell::RefCell::new(CustomElements::new( |customelements, tag, element| match tag { "hello-world" => HelloWorld::create(customelements, element), _ => console::error(&format!("unknown web component {}", tag)), })) }

[no_mangle]

pub fn main() -> () { // This function starts listening for hello-world components CUSTOMELEMENTS.with(|c| { c.borrowmut().define("hello-world"); }); }

[no_mangle]

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

Let's make a clock

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::(id).timer(); }), ); }

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

Observing Attributes

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