feat(slhx): add concise public render helper

Expose slhx::render(view) as the short SafeHtml composition helper and keep render_html(view) as a compatibility alias, matching generated modules' lean page-building path.

req: dx/006

req: html_safety/002
This commit is contained in:
slhx agent
2026-06-01 23:15:31 +02:00
parent 0d4a643759
commit f7d9f820e2
2 changed files with 30 additions and 7 deletions
+1 -1
View File
@@ -76,7 +76,7 @@ slhx competes with React by making frontend frameworks unnecessary for most apps
005 Error messages must explain fixes in author language, not internal language. Say “add `h-key="todo.id"` to this `h-for`”, not “missing ScopeKey for ResourceRef”.
### req: dx/006
006 Generated resource methods are the preferred authoring API: `slots::todo_list.render(view)`, `slots::card.replace(key, view)`, `slots::count.text(42)`, `atoms::user.set(user)`. Generated view modules also expose `render(view)` for trusted hemplate-to-`SafeHtml` page and fragment composition; `render_html(view)` remains as an explicit compatibility alias. These return `impl IntoEffect` or `SafeHtml` at the boundary. Raw `Effect` constructors, opcodes, and `EffectWriter` remain low-level. [north_star]
006 Generated resource methods are the preferred authoring API: `slots::todo_list.render(view)`, `slots::card.replace(key, view)`, `slots::count.text(42)`, `atoms::user.set(user)`. The public facade and generated view modules expose `render(view)` for trusted hemplate-to-`SafeHtml` page and fragment composition; `render_html(view)` remains as an explicit compatibility alias. These return `impl IntoEffect` or `SafeHtml` at the boundary. Raw `Effect` constructors, opcodes, and `EffectWriter` remain low-level. [north_star]
### req: dx/007
007 Tuple composition of `IntoEffect` is the canonical batch syntax: `(a, b, c)` implements `IntoEffect` up to arity 12. `Effect::batch((...))` is available but not required for the happy path.
+29 -6
View File
@@ -6,13 +6,17 @@
pub use slhx_core::*;
pub use slhx_derive::{app, component, form, handler, surface};
pub fn render_html(view: &impl hemplate::Hemplate) -> SafeHtml {
pub fn render(view: &impl hemplate::Hemplate) -> SafeHtml {
let mut html = String::new();
view.render_into(&mut html)
.expect("hemplate view renders into slhx effect payload");
SafeHtml::trusted(html)
}
pub fn render_html(view: &impl hemplate::Hemplate) -> SafeHtml {
render(view)
}
pub trait RenderSlotExt {
fn render(self, view: &impl hemplate::Hemplate) -> Effect;
@@ -26,7 +30,7 @@ pub trait RenderSlotExt {
impl<T> RenderSlotExt for Slot<T> {
fn render(self, view: &impl hemplate::Hemplate) -> Effect {
self.html(render_html(view))
self.html(render(view))
}
}
@@ -62,15 +66,15 @@ where
K: ToString,
{
fn append(self, key: K, view: &impl hemplate::Hemplate) -> Effect {
self.append_html(key, render_html(view))
self.append_html(key, render(view))
}
fn prepend(self, key: K, view: &impl hemplate::Hemplate) -> Effect {
self.prepend_html(key, render_html(view))
self.prepend_html(key, render(view))
}
fn replace(self, key: K, view: &impl hemplate::Hemplate) -> Effect {
self.replace_html(key, render_html(view))
self.replace_html(key, render(view))
}
}
@@ -80,6 +84,25 @@ pub mod prelude {
CssClasses, Effect, EventName, Form, FormModel, FormValue, Handle, IntoEffect, KeyedSlot,
ParamName, Slot,
};
pub use crate::{render_html, RenderKeyedSlotExt, RenderSlotExt};
pub use crate::{render, render_html, RenderKeyedSlotExt, RenderSlotExt};
pub use slhx_derive::{app, component, form, handler, surface};
}
#[cfg(test)]
mod tests {
struct InlineView;
impl hemplate::Hemplate for InlineView {
fn render_into(&self, out: &mut String) -> Result<(), hemplate::error::HemplateError> {
out.push_str("<strong>ok</strong>");
Ok(())
}
}
#[test]
fn render_is_the_short_safe_html_helper() {
// req: dx/006 req: html_safety/002
assert_eq!(crate::render(&InlineView).as_str(), "<strong>ok</strong>");
assert_eq!(crate::render_html(&InlineView).as_str(), "<strong>ok</strong>");
}
}