use serde::{Deserialize, Serialize};
use serde_json::Value;
use super::handler::HandlerRef;
use super::signal::SignalId;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum View {
Text(String),
Dynamic(Dynamic),
Element(Element),
Fragment(Fragment),
Component(ComponentMarker),
Island(Island),
Slot(SlotView),
Raw(String),
Empty,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Element {
pub tag: String,
pub attrs: Vec<Attr>,
pub children: Vec<Child>,
pub dom_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Fragment {
pub children: Vec<Child>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentMarker {
pub name: String,
pub view: Box<View>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SlotView {
pub name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Island {
pub chunk_id: String,
pub instance_id: String,
pub signal_ids: Vec<SignalId>,
pub view: Box<View>,
pub props: Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Child {
View(View),
Text(String),
}
impl From<View> for Child {
fn from(v: View) -> Self {
Child::View(v)
}
}
impl From<&str> for Child {
fn from(s: &str) -> Self {
Child::Text(s.to_string())
}
}
impl From<String> for Child {
fn from(s: String) -> Self {
Child::Text(s)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Attr {
pub name: String,
pub value: AttrValue,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum AttrValue {
Static(String),
Dynamic {
signal: SignalId,
format: Option<String>,
},
Handler(HandlerRef),
Bool(bool),
PreventDefault(String),
StopPropagation(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Dynamic {
pub signal: SignalId,
pub format: Option<String>,
pub snapshot: Value,
}
impl View {
pub fn text(s: impl Into<String>) -> Self {
View::Text(s.into())
}
pub fn raw(html: impl Into<String>) -> Self {
View::Raw(html.into())
}
pub fn empty() -> Self {
View::Empty
}
pub fn element(tag: impl Into<String>) -> ElementBuilder {
ElementBuilder {
element: Element {
tag: tag.into(),
..Default::default()
},
}
}
pub fn fragment(children: Vec<Child>) -> Self {
View::Fragment(Fragment { children })
}
pub fn slot(name: Option<String>) -> Self {
View::Slot(SlotView { name })
}
}
pub struct ElementBuilder {
element: Element,
}
impl ElementBuilder {
pub fn attr(mut self, name: impl Into<String>, value: AttrValue) -> Self {
self.element.attrs.push(Attr {
name: name.into(),
value,
});
self
}
pub fn child(mut self, child: impl Into<Child>) -> Self {
self.element.children.push(child.into());
self
}
pub fn children(mut self, children: impl IntoIterator<Item = Child>) -> Self {
self.element.children.extend(children);
self
}
pub fn dom_id(mut self, id: impl Into<String>) -> Self {
self.element.dom_id = Some(id.into());
self
}
pub fn build(self) -> View {
View::Element(self.element)
}
}