use crate::signal::RenderingState;
use crate::state::{ComponentData, State};
use crate::type_macros;
pub trait Element<C>: 'static {
#[doc(hidden)]
fn render_box(
self: Box<Self>,
ctx: &mut State<C>,
render_state: &mut RenderingState,
) -> web_sys::Node;
#[doc(hidden)]
fn render(self, ctx: &mut State<C>, render_state: &mut RenderingState) -> web_sys::Node
where
Self: Sized,
{
Box::new(self).render_box(ctx, render_state)
}
}
impl<C> Element<C> for web_sys::Node {
fn render_box(
self: Box<Self>,
_ctx: &mut State<C>,
_render_state: &mut RenderingState,
) -> web_sys::Node {
*self
}
}
pub struct Comment;
impl<C> Element<C> for Comment {
fn render_box(
self: Box<Self>,
_ctx: &mut State<C>,
_render_state: &mut RenderingState,
) -> web_sys::Node {
#[expect(clippy::expect_used, reason = "I have no clue how this can fail.")]
web_sys::Comment::new()
.expect("Failed to make comment")
.into()
}
}
impl<T: Element<C>, C: ComponentData> Element<C> for Option<T> {
fn render_box(
self: Box<Self>,
ctx: &mut State<C>,
render_state: &mut RenderingState,
) -> web_sys::Node {
match *self {
Some(element) => element.render(ctx, render_state),
None => Element::<C>::render(Comment, ctx, render_state),
}
}
}
impl<T: Element<C>, E: Element<C>, C: ComponentData> Element<C> for Result<T, E> {
fn render_box(
self: Box<Self>,
ctx: &mut State<C>,
render_state: &mut RenderingState,
) -> web_sys::Node {
match *self {
Ok(element) => element.render(ctx, render_state),
Err(element) => element.render(ctx, render_state),
}
}
}
macro_rules! string_element {
($t:ty) => {
impl<C> Element<C> for $t {
fn render_box(
self: Box<Self>,
_ctx: &mut State<C>,
_render_state: &mut RenderingState,
) -> web_sys::Node {
let text = web_sys::Text::new().expect("Failed to make text");
text.set_text_content(Some(&self));
text.into()
}
}
};
}
type_macros::strings!(string_element);
macro_rules! int_element {
($T:ident, $fmt:ident) => {
impl<C> Element<C> for $T {
fn render_box(
self: Box<Self>,
_ctx: &mut State<C>,
_render_state: &mut RenderingState,
) -> web_sys::Node {
let mut buffer = $fmt::Buffer::new();
let result = buffer.format(*self);
let text = web_sys::Text::new().expect("Failed to make text");
text.set_text_content(Some(result));
text.into()
}
}
};
}
type_macros::numerics!(int_element);
#[cfg(feature = "either")]
mod either_element {
use either::Either;
use super::{Element, RenderingState, State};
impl<A: Element<C>, B: Element<C>, C> Element<C> for Either<A, B> {
fn render_box(
self: Box<Self>,
ctx: &mut State<C>,
render_state: &mut RenderingState,
) -> web_sys::Node {
match *self {
Either::Left(a) => a.render(ctx, render_state),
Either::Right(b) => b.render(ctx, render_state),
}
}
}
}