Files
hemx/slhx/src/lib.rs
T
slhx agent ee6045aec5 feat(build): generate keyed view commands
Add lower-aware generated append/prepend/replace helpers for keyed slots, move the v0 keyed todo example off the facade extension trait, and keep beginner examples from importing lower-level render shortcuts.

req: dx/006

req: codegen/002

req: public_api/003

req: examples/003
2026-06-02 03:05:37 +02:00

119 lines
3.3 KiB
Rust

//! Public authoring facade for slhx applications.
//!
//! Most application code should depend on this crate, use the proc-macros from
//! here, and import generated resources through `#[slhx::surface]`.
pub use slhx_core::*;
pub use slhx_derive::{app, component, form, handler, surface};
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;
fn render_view(self, view: &impl hemplate::Hemplate) -> Effect
where
Self: Sized,
{
self.render(view)
}
}
impl<T> RenderSlotExt for Slot<T> {
fn render(self, view: &impl hemplate::Hemplate) -> Effect {
self.html(render(view))
}
}
pub trait RenderKeyedSlotExt<K> {
fn append(self, key: K, view: &impl hemplate::Hemplate) -> Effect;
fn prepend(self, key: K, view: &impl hemplate::Hemplate) -> Effect;
fn replace(self, key: K, view: &impl hemplate::Hemplate) -> Effect;
fn append_view(self, key: K, view: &impl hemplate::Hemplate) -> Effect
where
Self: Sized,
{
self.append(key, view)
}
fn prepend_view(self, key: K, view: &impl hemplate::Hemplate) -> Effect
where
Self: Sized,
{
self.prepend(key, view)
}
fn replace_view(self, key: K, view: &impl hemplate::Hemplate) -> Effect
where
Self: Sized,
{
self.replace(key, view)
}
}
impl<K, T> RenderKeyedSlotExt<K> for KeyedSlot<K, T>
where
K: ToString,
{
fn append(self, key: K, view: &impl hemplate::Hemplate) -> Effect {
self.append_html(key, render(view))
}
fn prepend(self, key: K, view: &impl hemplate::Hemplate) -> Effect {
self.prepend_html(key, render(view))
}
fn replace(self, key: K, view: &impl hemplate::Hemplate) -> Effect {
self.replace_html(key, render(view))
}
}
pub mod prelude {
pub use slhx_core::{
navigate, push, redirect, replace, Atom, BuildFingerprint, ComponentRef, CssClass,
CssClasses, Effect, EventName, Form, FormModel, FormValue, Handle, IntoEffect, KeyedSlot,
ParamName, SafeHtml, Slot,
};
pub use crate::{render, render_html};
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>");
}
#[test]
fn prelude_exports_safe_html_for_page_composition() {
// req: dx/006 req: html_safety/002
use crate::prelude::*;
let html = SafeHtml::join([render(&InlineView)]);
assert_eq!(html.as_str(), "<strong>ok</strong>");
}
}