Skip to content

Commit

Permalink
feat: components
Browse files Browse the repository at this point in the history
  • Loading branch information
mrchantey committed Jan 15, 2025
1 parent a2a122f commit 5d60feb
Show file tree
Hide file tree
Showing 12 changed files with 195 additions and 141 deletions.
8 changes: 6 additions & 2 deletions crates/sweet_core/src/rsx/html_partial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,22 @@ pub enum Node {
/// a rust block, contents is reconciled by renderer
TextBlock,
/// an rust value that implements [Rsx] contents is reconciled by renderer
Component(Element),
/// The children here are the 'children' of the component
Component(Vec<Node>),
}

impl Node {
pub fn to_string_placeholder(&self) -> String {

match self {
Node::Doctype => "<!DOCTYPE html>".to_string(),
Node::Comment(s) => format!("<!--{}-->", s),
Node::Element(e) => e.to_string_placeholder(),
Node::Text(s) => s.clone(),
Node::TextBlock => HtmlPartial::PLACEHOLDER.to_string(),
Node::Component(e) => e.to_string_placeholder(),
Node::Component(c) => {
c.iter().map(|c| c.to_string_placeholder()).collect()
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/sweet_core/src/rsx/html_partial_quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl ToTokens for Node {
Node::Element(e) => quote!(Node::Element(#e)),
Node::Text(s) => quote!(Node::Text(#s.to_string())),
Node::TextBlock => quote!(Node::TextBlock),
Node::Component(e) => quote!(Node::Component(#e)),
Node::Component(c) => quote!(Node::Component(Vec::from([#(#c,)*]))),
}
.to_tokens(tokens);
}
Expand Down
14 changes: 10 additions & 4 deletions crates/sweet_core/src/rsx/rsx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ impl Rsx for () {
fn into_parts(self) -> RsxParts { RsxParts::default() }
}

// pub trait Component {
// type Props;
// fn from_props(props: Self::Props) -> Self;
// fn render(self) -> impl Rsx;
// }


pub trait Component {
fn render(self) -> impl Rsx;
}
pub trait Props {
type Component;
fn new() -> Self;
fn build() -> Self::Component;
}
23 changes: 7 additions & 16 deletions crates/sweet_core/src/rsx/rsx_parts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ use strum_macros::AsRefStr;
/// The rust, html and css extracted from an `rsx!` macro.
/// Note that the outputted html and css is not final,
/// it contains a placeholder that is filled in the render step.
#[derive(Default)]



#[derive(Debug, Default)]
pub struct RsxParts {
/// The rust blocks extracted from the rsx! macro,
/// collected via Depth First Search traversal.
Expand All @@ -19,18 +16,6 @@ pub struct RsxParts {

impl RsxParts {}

impl std::fmt::Debug for RsxParts {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RsxParts")
.field(
"rust",
&self.rust.iter().map(|r| r.as_ref()).collect::<Vec<_>>(),
)
.field("html", &self.html)
.finish()
}
}

/// The event or the indentifiers/blocks `ToString`.
#[derive(AsRefStr)]
pub enum RsxRust {
Expand All @@ -50,6 +35,12 @@ pub enum RsxRust {
Component(RsxParts),
}

impl std::fmt::Debug for RsxRust {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(self.as_ref()).finish()
}
}

/// Either provide data in a file or stored as a string,
/// used for css and html.
/// Defaults to Inline(String::default())
Expand Down
6 changes: 3 additions & 3 deletions crates/sweet_render/src/render/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
pub mod rsx_visitor;
#[allow(unused_imports)]
pub use self::rsx_visitor::*;
pub mod render_plugin;
#[allow(unused_imports)]
pub use self::render_plugin::*;
pub mod rsx_renderer;
#[allow(unused_imports)]
pub use self::rsx_renderer::*;
pub mod rsx_visitor;
#[allow(unused_imports)]
pub use self::rsx_visitor::*;
pub mod sweet_rsx_visitor;
#[allow(unused_imports)]
pub use self::sweet_rsx_visitor::*;
110 changes: 87 additions & 23 deletions crates/sweet_render/src/render/rsx_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,25 +82,25 @@ impl<'a, V: RsxVisitor> RsxRenderer<'a, V> {
Err(ParseError::hydration("expected text block", "block"))
}
}
Node::Component(el) => self.render_component(el),
Node::Component(children) => self.render_component(children),
}
}
/// 1.
fn render_component(&mut self, el: &mut Element) -> ParseResult<String> {
if let RsxRust::Component(component) = self.get_rust()? {
//1. render open tag
let mut str = self.render_element_open(el)?;
// 2. render direct children 'passed in' by component parent
str.push_str(&self.render_nodes(&mut el.children)?);
// 3. render component children
let (component_children_str, component_children) =
RsxRenderer::render(self.visitor, component)?;
str.push_str(&component_children_str);
el.children.extend(component_children.nodes);
str.push_str(&self.render_element_close(el)?);
Ok(str)
} else {
Err(ParseError::hydration("Component", &el.tag))
fn render_component(
&mut self,
children: &mut Vec<Node>,
) -> ParseResult<String> {
match self.get_rust()? {
RsxRust::Component(component) => {
// render 'passed in' children first
let mut str = self.render_nodes(children)?;
let (component_children_str, component_children) =
RsxRenderer::render(self.visitor, component)?;
str.push_str(&component_children_str);
children.extend(component_children.nodes);
Ok(str)
}
other => Err(ParseError::hydration("Component", &other)),
}
}

Expand Down Expand Up @@ -190,23 +190,87 @@ mod test {
use crate::render::SweetRsxVisitor;
use sweet::prelude::*;


fn render(rsx: impl Rsx) -> (String, HtmlPartial) {
let mut visitor = SweetRsxVisitor::default();
RsxRenderer::render(&mut visitor, rsx).unwrap()
}

#[test]
fn doctype() {
let (str, _) = render(rsx! { <!DOCTYPE html> });
expect(str).to_be("<!DOCTYPE html>");
}

#[test]
fn comment() {
let (str, _) = render(rsx! { <!-- "hello" --> });
expect(str).to_be("<!-- hello -->");
}

#[test]
fn text() {
let (str, _) = render(rsx! { "hello" });
expect(str).to_be("hello");
}

#[test]
fn element() {
let (str, _) = render(rsx! { <div></div> });
expect(str).to_be("<div></div>");
}
#[test]
fn element_self_closing() {
let (str, _) = render(rsx! { <br/> });
expect(str).to_be("<br/>");
}
#[test]
fn element_children() {
let (str, _) = render(rsx! { <div>hello</div> });
expect(str).to_be("<div>hello</div>");
}

#[test]
fn works() {
fn text_block() {
let value = "hello";
let (str, _) = render(rsx! { {value} });
expect(str).to_be("hello");
}

#[test]
fn component() {
struct Child {
value: u32,
}
impl Rsx for Child {
fn into_parts(self) -> RsxParts {
rsx! {
<div>{self.value}</div>
}
}
}
let (str, _) = render(rsx! { <Child value=7/> });
expect(str).to_be(
"<div data-sweet-id=\"1\" data-sweet-blocks=\"0,0\">7</div>",
);
}


#[test]
fn nexted() {
let onclick = |_| {};
let world = "mars";
let rsx = rsx! {
<div onclick>
<p>hello {world}</p>
</div>
};
expect(format!("{:?}", rsx.rust)).to_be("[Event, InnerText]");

println!("rsx: '{:#?}'", rsx);

let mut visitor = SweetRsxVisitor::default();
let (rendered_str, rendered_tree) =
RsxRenderer::render(&mut visitor, rsx).unwrap();
println!("rendered_tree: '{:#?}'", rendered_tree);
println!("html: '{}'", rendered_str);
let (str, _) = render(rsx);
// println!("rendered_tree: '{:#?}'", rendered_tree);
// println!("html: '{}'", rendered_str);

// expect(true).to_be_false();
}
Expand Down
21 changes: 21 additions & 0 deletions crates/sweet_rsx/examples/rsx_macro.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
use sweet::prelude::rsx;
use sweet::prelude::Rsx;
use sweet::prelude::RsxParts;


struct Component {
value: u32,
}
impl Rsx for Component {
fn into_parts(self) -> RsxParts {
rsx! {
<div>{self.value}</div>
}
}
}


fn main() {
let onclick = |_| {};

let _foo = rsx! {
<div onclick>
<p>hello</p>
<Component value=7/>
</div>
};

let str = _foo.html.load().unwrap().to_string_placeholder();
println!("{}", str);
}
3 changes: 0 additions & 3 deletions crates/sweet_rsx/src/parse_rsx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ pub use self::rsx_file_visitor::*;
pub mod rsx_parser;
#[allow(unused_imports)]
pub use self::rsx_parser::*;
pub mod sweet_rsx_plugin;
#[allow(unused_imports)]
pub use self::sweet_rsx_plugin::*;
pub mod walk_nodes;
#[allow(unused_imports)]
pub use self::walk_nodes::*;
16 changes: 16 additions & 0 deletions crates/sweet_rsx/src/parse_rsx/rsx_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,19 @@ pub fn macro_or_err(expr: &Expr) -> syn::Result<&syn::Macro> {
Err(syn::Error::new_spanned(expr, "expected macro"))
}
}
#[cfg(test)]
mod test {
use sweet::prelude::*;

#[test]
fn event_order() {
let onclick = |_| {};
let world = "mars";
let rsx = rsx! {
<div onclick>
<p>hello {world}</p>
</div>
};
expect(format!("{:?}", rsx.rust)).to_be("[Event, InnerText]");
}
}
43 changes: 0 additions & 43 deletions crates/sweet_rsx/src/parse_rsx/sweet_rsx_plugin.rs

This file was deleted.

Loading

0 comments on commit 5d60feb

Please sign in to comment.