feat: Suspend on style: and class:

This commit is contained in:
Greg Johnston 2024-07-12 11:07:07 -04:00
parent 6290c42159
commit efd060c955
3 changed files with 116 additions and 9 deletions

View file

@ -1,9 +1,10 @@
use super::{ReactiveFunction, SharedReactiveFunction};
use super::{ReactiveFunction, SharedReactiveFunction, Suspend};
use crate::{html::class::IntoClass, renderer::DomRenderer};
use any_spawner::Executor;
use futures::FutureExt;
use reactive_graph::{effect::RenderEffect, signal::guards::ReadGuard};
use std::{
borrow::{Borrow, Cow},
ops::Deref,
borrow::Borrow, cell::RefCell, future::Future, ops::Deref, rc::Rc,
sync::Arc,
};
@ -692,3 +693,82 @@ mod stable {
class_signal!(ArcMemo);
class_signal!(ArcSignal);
}
impl<Fut, Rndr> IntoClass<Rndr> for Suspend<Fut>
where
Fut: Clone + Future + Send + 'static,
Fut::Output: IntoClass<Rndr>,
Rndr: DomRenderer + 'static,
{
type AsyncOutput = Fut::Output;
type State = Rc<RefCell<Option<<Fut::Output as IntoClass<Rndr>>::State>>>;
type Cloneable = Self;
type CloneableOwned = Self;
fn html_len(&self) -> usize {
0
}
fn to_html(self, style: &mut String) {
if let Some(inner) = self.0.now_or_never() {
inner.to_html(style);
} else {
panic!("You cannot use Suspend on an attribute outside Suspense");
}
}
fn hydrate<const FROM_SERVER: bool>(
self,
el: &<Rndr>::Element,
) -> Self::State {
let el = el.to_owned();
let state = Rc::new(RefCell::new(None));
Executor::spawn_local({
let state = Rc::clone(&state);
async move {
*state.borrow_mut() =
Some(self.0.await.hydrate::<FROM_SERVER>(&el));
}
});
state
}
fn build(self, el: &<Rndr>::Element) -> Self::State {
let el = el.to_owned();
let state = Rc::new(RefCell::new(None));
Executor::spawn_local({
let state = Rc::clone(&state);
async move {
*state.borrow_mut() = Some(self.0.await.build(&el));
}
});
state
}
fn rebuild(self, state: &mut Self::State) {
Executor::spawn_local({
let state = Rc::clone(&state);
async move {
let value = self.0.await;
let mut state = state.borrow_mut();
if let Some(state) = state.as_mut() {
value.rebuild(state);
}
}
});
}
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
fn dry_resolve(&mut self) {}
async fn resolve(self) -> Self::AsyncOutput {
self.0.await
}
}

View file

@ -1,8 +1,9 @@
use super::{ReactiveFunction, SharedReactiveFunction, Suspend};
use crate::{html::style::IntoStyle, renderer::DomRenderer};
use any_spawner::Executor;
use futures::FutureExt;
use reactive_graph::effect::RenderEffect;
use std::{borrow::Cow, future::Future};
use std::{borrow::Cow, cell::RefCell, future::Future, rc::Rc};
impl<F, S, R> IntoStyle<R> for (&'static str, F)
where
@ -432,7 +433,7 @@ where
Rndr: DomRenderer + 'static,
{
type AsyncOutput = Fut::Output;
type State = ();
type State = Rc<RefCell<Option<<Fut::Output as IntoStyle<Rndr>>::State>>>;
type Cloneable = Self;
type CloneableOwned = Self;
@ -448,15 +449,41 @@ where
self,
el: &<Rndr>::Element,
) -> Self::State {
todo!()
let el = el.to_owned();
let state = Rc::new(RefCell::new(None));
Executor::spawn_local({
let state = Rc::clone(&state);
async move {
*state.borrow_mut() =
Some(self.0.await.hydrate::<FROM_SERVER>(&el));
}
});
state
}
fn build(self, el: &<Rndr>::Element) -> Self::State {
todo!()
let el = el.to_owned();
let state = Rc::new(RefCell::new(None));
Executor::spawn_local({
let state = Rc::clone(&state);
async move {
*state.borrow_mut() = Some(self.0.await.build(&el));
}
});
state
}
fn rebuild(self, state: &mut Self::State) {
todo!()
Executor::spawn_local({
let state = Rc::clone(&state);
async move {
let value = self.0.await;
let mut state = state.borrow_mut();
if let Some(state) = state.as_mut() {
value.rebuild(state);
}
}
});
}
fn into_cloneable(self) -> Self::Cloneable {

View file

@ -1,5 +1,5 @@
use crate::{
html::{attribute::Attribute, style::IntoStyle},
html::attribute::Attribute,
hydration::Cursor,
renderer::Renderer,
ssr::StreamBuilder,