use crate::{Context, Event, Html, LiveResult};
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ComponentId(String);
impl ComponentId {
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for ComponentId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl From<&str> for ComponentId {
fn from(value: &str) -> Self {
Self::new(value)
}
}
impl From<String> for ComponentId {
fn from(value: String) -> Self {
Self::new(value)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ComponentRender {
id: ComponentId,
html: Html,
}
impl ComponentRender {
pub fn new(id: impl Into<ComponentId>, html: Html) -> Self {
Self {
id: id.into(),
html,
}
}
pub fn id(&self) -> &ComponentId {
&self.id
}
pub fn html(&self) -> &Html {
&self.html
}
pub fn into_parts(self) -> (ComponentId, Html) {
(self.id, self.html)
}
}
pub trait LiveComponent: Send + 'static {
fn id(&self) -> ComponentId;
fn mount(&mut self, _ctx: &mut Context) -> LiveResult {
Ok(())
}
fn handle_event(&mut self, _event: Event, _ctx: &mut Context) -> LiveResult {
Ok(())
}
fn render(&self) -> Html;
}
#[cfg(test)]
mod tests {
use super::{ComponentId, ComponentRender, LiveComponent};
use crate::{Context, Event, Html};
#[derive(Default)]
struct StubComponent;
impl LiveComponent for StubComponent {
fn id(&self) -> ComponentId {
ComponentId::new("stub")
}
fn render(&self) -> Html {
Html::new("<div>stub</div>")
}
}
#[test]
fn component_id_and_render_parts_round_trip() {
let render = ComponentRender::new("item-1", Html::new("<p>x</p>"));
assert_eq!(render.id().as_str(), "item-1");
assert_eq!(render.id().to_string(), "item-1");
assert_eq!(render.html().as_str(), "<p>x</p>");
let (id, html) = render.into_parts();
assert_eq!(id.as_str(), "item-1");
assert_eq!(html.as_str(), "<p>x</p>");
let from_string = ComponentId::from(String::from("item-2"));
assert_eq!(from_string.as_str(), "item-2");
}
#[test]
fn live_component_default_callbacks_return_ok() {
let mut component = StubComponent;
let mut ctx = Context::new("root");
assert!(component.mount(&mut ctx).is_ok());
assert!(component.handle_event(Event::new("noop"), &mut ctx).is_ok());
assert_eq!(component.id().as_str(), "stub");
assert_eq!(component.render().as_str(), "<div>stub</div>");
}
}