mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-27 09:54:41 -05:00
implement AddAnyAttr for AnyView (#3562)
This commit is contained in:
493
Cargo.lock
generated
493
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@ async fn clear() {
|
||||
// note that we start at the initial value of 10
|
||||
let _dispose = mount_to(
|
||||
test_wrapper.clone().unchecked_into(),
|
||||
|| view! { <SimpleCounter initial_value=10 step=1 /> },
|
||||
|| view! { <SimpleCounter initial_value=10 step=1/> },
|
||||
);
|
||||
|
||||
// now we extract the buttons by iterating over the DOM
|
||||
@@ -59,9 +59,9 @@ async fn clear() {
|
||||
// .into_view() here is just a convenient way of specifying "use the regular DOM renderer"
|
||||
.into_view()
|
||||
// views are lazy -- they describe a DOM tree but don't create it yet
|
||||
// calling .build(None) will actually build the DOM elements
|
||||
.build(None)
|
||||
// .build(None) returned an ElementState, which is a smart pointer for
|
||||
// calling .build() will actually build the DOM elements
|
||||
.build()
|
||||
// .build() returned an ElementState, which is a smart pointer for
|
||||
// a DOM element. So we can still just call .outer_html(), which access the outerHTML on
|
||||
// the actual DOM element
|
||||
.outer_html()
|
||||
@@ -87,7 +87,7 @@ async fn inc() {
|
||||
|
||||
let _dispose = mount_to(
|
||||
test_wrapper.clone().unchecked_into(),
|
||||
|| view! { <SimpleCounter initial_value=0 step=1 /> },
|
||||
|| view! { <SimpleCounter initial_value=0 step=1/> },
|
||||
);
|
||||
|
||||
// You can do testing with vanilla DOM operations
|
||||
@@ -150,7 +150,7 @@ async fn inc() {
|
||||
}
|
||||
}
|
||||
.into_view()
|
||||
.build(None)
|
||||
.build()
|
||||
.outer_html()
|
||||
);
|
||||
|
||||
@@ -173,7 +173,7 @@ async fn inc() {
|
||||
}
|
||||
}
|
||||
.into_view()
|
||||
.build(None)
|
||||
.build()
|
||||
.outer_html()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ use crate::attr::{
|
||||
Attribute, NextAttribute,
|
||||
};
|
||||
use leptos::prelude::*;
|
||||
use tachys::view::any_view::ExtraAttrsMut;
|
||||
|
||||
/// Function stored to build/rebuild the wrapped children when attributes are added.
|
||||
type ChildBuilder<T> = dyn Fn(AnyAttribute) -> T + Send + Sync + 'static;
|
||||
@@ -44,7 +43,7 @@ pub fn AttributeInterceptor<Chil, T>(
|
||||
) -> impl IntoView
|
||||
where
|
||||
Chil: Fn(AnyAttribute) -> T + Send + Sync + 'static,
|
||||
T: IntoView + 'static,
|
||||
T: IntoView,
|
||||
{
|
||||
AttributeInterceptorInner::new(children)
|
||||
}
|
||||
@@ -78,20 +77,16 @@ impl<T: IntoView> AttributeInterceptorInner<T, ()> {
|
||||
impl<T: IntoView, A: Attribute> Render for AttributeInterceptorInner<T, A> {
|
||||
type State = <T as Render>::State;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
self.children.build(extra_attrs)
|
||||
fn build(self) -> Self::State {
|
||||
self.children.build()
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
self.children.rebuild(state, extra_attrs);
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
self.children.rebuild(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IntoView + 'static, A> AddAnyAttr for AttributeInterceptorInner<T, A>
|
||||
impl<T: IntoView, A> AddAnyAttr for AttributeInterceptorInner<T, A>
|
||||
where
|
||||
A: Attribute,
|
||||
{
|
||||
@@ -119,23 +114,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IntoView + 'static, A: Attribute> RenderHtml
|
||||
for AttributeInterceptorInner<T, A>
|
||||
{
|
||||
impl<T: IntoView, A: Attribute> RenderHtml for AttributeInterceptorInner<T, A> {
|
||||
type AsyncOutput = T::AsyncOutput;
|
||||
type Owned = AttributeInterceptorInner<T, A::CloneableOwned>;
|
||||
|
||||
const MIN_LENGTH: usize = T::MIN_LENGTH;
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
self.children.dry_resolve(extra_attrs)
|
||||
fn dry_resolve(&mut self) {
|
||||
self.children.dry_resolve()
|
||||
}
|
||||
|
||||
fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> impl std::future::Future<Output = Self::AsyncOutput> + Send {
|
||||
self.children.resolve(extra_attrs)
|
||||
self.children.resolve()
|
||||
}
|
||||
|
||||
fn to_html_with_buf(
|
||||
@@ -144,14 +135,14 @@ impl<T: IntoView + 'static, A: Attribute> RenderHtml
|
||||
position: &mut leptos::tachys::view::Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
_extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
self.children.to_html_with_buf(
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
extra_attrs,
|
||||
vec![],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -159,17 +150,7 @@ impl<T: IntoView + 'static, A: Attribute> RenderHtml
|
||||
self,
|
||||
cursor: &leptos::tachys::hydration::Cursor,
|
||||
position: &leptos::tachys::view::PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
self.children
|
||||
.hydrate::<FROM_SERVER>(cursor, position, extra_attrs)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
AttributeInterceptorInner {
|
||||
children_builder: self.children_builder,
|
||||
children: self.children,
|
||||
attributes: self.attributes.into_cloneable_owned(),
|
||||
}
|
||||
self.children.hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ use tachys::{
|
||||
reactive_graph::OwnedView,
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Mountable, Position,
|
||||
PositionState, Render, RenderHtml,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
},
|
||||
};
|
||||
use throw_error::{Error, ErrorHook, ErrorId};
|
||||
@@ -163,6 +163,14 @@ where
|
||||
self.children.insert_before_this(child)
|
||||
}
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<tachys::renderer::types::Element> {
|
||||
if let Some(fallback) = &self.fallback {
|
||||
fallback.elements()
|
||||
} else {
|
||||
self.children.elements()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Chil, FalFn, Fal> Render for ErrorBoundaryView<Chil, FalFn>
|
||||
@@ -173,10 +181,10 @@ where
|
||||
{
|
||||
type State = RenderEffect<ErrorBoundaryViewState<Chil::State, Fal::State>>;
|
||||
|
||||
fn build(mut self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(mut self) -> Self::State {
|
||||
let hook = Arc::clone(&self.hook);
|
||||
let _hook = throw_error::set_error_hook(Arc::clone(&hook));
|
||||
let mut children = Some(self.children.build(extra_attrs.clone()));
|
||||
let mut children = Some(self.children.build());
|
||||
RenderEffect::new(
|
||||
move |prev: Option<
|
||||
ErrorBoundaryViewState<Chil::State, Fal::State>,
|
||||
@@ -193,8 +201,7 @@ where
|
||||
// yes errors, and was showing children
|
||||
(false, None) => {
|
||||
state.fallback = Some(
|
||||
(self.fallback)(self.errors.clone())
|
||||
.build(extra_attrs.clone()),
|
||||
(self.fallback)(self.errors.clone()).build(),
|
||||
);
|
||||
state
|
||||
.children
|
||||
@@ -208,10 +215,8 @@ where
|
||||
}
|
||||
state
|
||||
} else {
|
||||
let fallback = (!self.errors_empty.get()).then(|| {
|
||||
(self.fallback)(self.errors.clone())
|
||||
.build(extra_attrs.clone())
|
||||
});
|
||||
let fallback = (!self.errors_empty.get())
|
||||
.then(|| (self.fallback)(self.errors.clone()).build());
|
||||
ErrorBoundaryViewState {
|
||||
children: children.take().unwrap(),
|
||||
fallback,
|
||||
@@ -221,12 +226,8 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
let new = self.build(extra_attrs);
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let new = self.build();
|
||||
let mut old = std::mem::replace(state, new);
|
||||
old.insert_before_this(state);
|
||||
old.unmount();
|
||||
@@ -275,18 +276,14 @@ where
|
||||
Fal: RenderHtml + Send + 'static,
|
||||
{
|
||||
type AsyncOutput = ErrorBoundaryView<Chil::AsyncOutput, FalFn>;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = Chil::MIN_LENGTH;
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
self.children.dry_resolve(extra_attrs);
|
||||
fn dry_resolve(&mut self) {
|
||||
self.children.dry_resolve();
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
let ErrorBoundaryView {
|
||||
hook,
|
||||
boundary_id,
|
||||
@@ -300,7 +297,7 @@ where
|
||||
hook,
|
||||
boundary_id,
|
||||
errors_empty,
|
||||
children: children.resolve(extra_attrs).await,
|
||||
children: children.resolve().await,
|
||||
fallback,
|
||||
errors,
|
||||
}
|
||||
@@ -312,7 +309,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
// first, attempt to serialize the children to HTML, then check for errors
|
||||
let _hook = throw_error::set_error_hook(self.hook);
|
||||
@@ -347,7 +344,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -384,7 +381,6 @@ where
|
||||
mut self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let mut children = Some(self.children);
|
||||
let hook = Arc::clone(&self.hook);
|
||||
@@ -406,8 +402,7 @@ where
|
||||
// yes errors, and was showing children
|
||||
(false, None) => {
|
||||
state.fallback = Some(
|
||||
(self.fallback)(self.errors.clone())
|
||||
.build(extra_attrs.clone()),
|
||||
(self.fallback)(self.errors.clone()).build(),
|
||||
);
|
||||
state
|
||||
.children
|
||||
@@ -424,23 +419,15 @@ where
|
||||
let children = children.take().unwrap();
|
||||
let (children, fallback) = if self.errors_empty.get() {
|
||||
(
|
||||
children.hydrate::<FROM_SERVER>(
|
||||
&cursor,
|
||||
&position,
|
||||
extra_attrs.clone(),
|
||||
),
|
||||
children.hydrate::<FROM_SERVER>(&cursor, &position),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
children.build(extra_attrs.clone()),
|
||||
children.build(),
|
||||
Some(
|
||||
(self.fallback)(self.errors.clone())
|
||||
.hydrate::<FROM_SERVER>(
|
||||
&cursor,
|
||||
&position,
|
||||
extra_attrs.clone(),
|
||||
),
|
||||
.hydrate::<FROM_SERVER>(&cursor, &position),
|
||||
),
|
||||
)
|
||||
};
|
||||
@@ -450,10 +437,6 @@ where
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -4,8 +4,8 @@ use tachys::{
|
||||
hydration::Cursor,
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Position, PositionState,
|
||||
Render, RenderHtml, ToTemplate,
|
||||
add_attr::AddAnyAttr, Position, PositionState, Render, RenderHtml,
|
||||
ToTemplate,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -76,34 +76,26 @@ where
|
||||
impl<T: Render> Render for View<T> {
|
||||
type State = T::State;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
self.inner.build(extra_attrs)
|
||||
fn build(self) -> Self::State {
|
||||
self.inner.build()
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
self.inner.rebuild(state, extra_attrs)
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
self.inner.rebuild(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RenderHtml> RenderHtml for View<T> {
|
||||
type AsyncOutput = T::AsyncOutput;
|
||||
type Owned = View<T::Owned>;
|
||||
|
||||
const MIN_LENGTH: usize = <T as RenderHtml>::MIN_LENGTH;
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
self.inner.resolve(extra_attrs).await
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self.inner.resolve().await
|
||||
}
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
self.inner.dry_resolve(extra_attrs);
|
||||
fn dry_resolve(&mut self) {
|
||||
self.inner.dry_resolve();
|
||||
}
|
||||
|
||||
fn to_html_with_buf(
|
||||
@@ -112,7 +104,7 @@ impl<T: RenderHtml> RenderHtml for View<T> {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
#[cfg(debug_assertions)]
|
||||
let vm = self.view_marker.to_owned();
|
||||
@@ -141,7 +133,7 @@ impl<T: RenderHtml> RenderHtml for View<T> {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -170,18 +162,8 @@ impl<T: RenderHtml> RenderHtml for View<T> {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
self.inner
|
||||
.hydrate::<FROM_SERVER>(cursor, position, extra_attrs)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
View {
|
||||
inner: self.inner.into_owned(),
|
||||
#[cfg(debug_assertions)]
|
||||
view_marker: self.view_marker,
|
||||
}
|
||||
self.inner.hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,6 @@ where
|
||||
view.hydrate::<true>(
|
||||
&Cursor::new(parent.unchecked_into()),
|
||||
&PositionState::default(),
|
||||
None,
|
||||
)
|
||||
});
|
||||
|
||||
@@ -125,7 +124,7 @@ where
|
||||
let owner = Owner::new();
|
||||
let mountable = owner.with(move || {
|
||||
let view = f().into_view();
|
||||
let mut mountable = view.build(None);
|
||||
let mut mountable = view.build();
|
||||
mountable.mount(&parent, None);
|
||||
mountable
|
||||
});
|
||||
@@ -153,7 +152,7 @@ where
|
||||
let owner = Owner::new();
|
||||
let mountable = owner.with(move || {
|
||||
let view = f();
|
||||
let mut mountable = view.build(None);
|
||||
let mut mountable = view.build();
|
||||
mountable.mount(parent, None);
|
||||
mountable
|
||||
});
|
||||
|
||||
@@ -25,7 +25,6 @@ use tachys::{
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr,
|
||||
any_view::ExtraAttrsMut,
|
||||
either::{EitherKeepAlive, EitherKeepAliveState},
|
||||
Mountable, Position, PositionState, Render, RenderHtml,
|
||||
},
|
||||
@@ -163,7 +162,7 @@ where
|
||||
OwnedViewState<EitherKeepAliveState<Chil::State, Fal::State>>,
|
||||
>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let mut children = Some(self.children);
|
||||
let mut fallback = Some(self.fallback);
|
||||
let none_pending = self.none_pending;
|
||||
@@ -188,20 +187,16 @@ where
|
||||
);
|
||||
|
||||
if let Some(mut state) = prev {
|
||||
this.rebuild(&mut state, extra_attrs.clone());
|
||||
this.rebuild(&mut state);
|
||||
state
|
||||
} else {
|
||||
this.build(extra_attrs.clone())
|
||||
this.build()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
let new = self.build(extra_attrs);
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let new = self.build();
|
||||
let mut old = std::mem::replace(state, new);
|
||||
old.insert_before_this(state);
|
||||
old.unmount();
|
||||
@@ -252,16 +247,12 @@ where
|
||||
// i.e., if this is the child of another Suspense during SSR, don't wait for it: it will handle
|
||||
// itself
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = Chil::MIN_LENGTH;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -271,7 +262,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
self.fallback.to_html_with_buf(
|
||||
buf,
|
||||
@@ -288,7 +279,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
mut extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -313,8 +304,7 @@ where
|
||||
provide_context(LocalResourceNotifier::from(local_tx));
|
||||
|
||||
// walk over the tree of children once to make sure that all resource loads are registered
|
||||
self.children
|
||||
.dry_resolve(ExtraAttrsMut::from_owned(&mut extra_attrs));
|
||||
self.children.dry_resolve();
|
||||
|
||||
// check the set of tasks to see if it is empty, now or later
|
||||
let eff = reactive_graph::effect::Effect::new_isomorphic({
|
||||
@@ -330,8 +320,7 @@ where
|
||||
}
|
||||
});
|
||||
|
||||
let mut fut = Box::pin(ScopedFuture::new(ErrorHookFuture::new({
|
||||
let mut extra_attrs = extra_attrs.clone();
|
||||
let mut fut = Box::pin(ScopedFuture::new(ErrorHookFuture::new(
|
||||
async move {
|
||||
// race the local resource notifier against the set of tasks
|
||||
//
|
||||
@@ -358,7 +347,7 @@ where
|
||||
// but in situations like a <For each=|| some_resource.snapshot()/> we actually
|
||||
// want to be able to 1) synchronously read a resource's value, but still 2) wait
|
||||
// for it to load before we render everything
|
||||
let mut children = Box::pin(self.children.resolve(ExtraAttrsMut::from_owned(&mut extra_attrs)).fuse());
|
||||
let mut children = Box::pin(self.children.resolve().fuse());
|
||||
|
||||
// we continue racing the children against the "do we have any local
|
||||
// resources?" Future
|
||||
@@ -377,8 +366,8 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})));
|
||||
},
|
||||
)));
|
||||
match fut.as_mut().now_or_never() {
|
||||
Some(Some(resolved)) => {
|
||||
Either::<Fal, _>::Right(resolved)
|
||||
@@ -449,7 +438,6 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let cursor = cursor.to_owned();
|
||||
let position = position.to_owned();
|
||||
@@ -478,21 +466,13 @@ where
|
||||
);
|
||||
|
||||
if let Some(mut state) = prev {
|
||||
this.rebuild(&mut state, extra_attrs.clone());
|
||||
this.rebuild(&mut state);
|
||||
state
|
||||
} else {
|
||||
this.hydrate::<FROM_SERVER>(
|
||||
&cursor,
|
||||
&position,
|
||||
extra_attrs.clone(),
|
||||
)
|
||||
this.hydrate::<FROM_SERVER>(&cursor, &position)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper that prevents [`Suspense`] from waiting for any resource reads that happen inside
|
||||
@@ -512,16 +492,12 @@ where
|
||||
{
|
||||
type State = T::State;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
(self.0)().build(extra_attrs)
|
||||
fn build(self) -> Self::State {
|
||||
(self.0)().build()
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
(self.0)().rebuild(state, extra_attrs);
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
(self.0)().rebuild(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,16 +525,12 @@ where
|
||||
T: RenderHtml + 'static,
|
||||
{
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = T::MIN_LENGTH;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -568,7 +540,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
(self.0)().to_html_with_buf(
|
||||
buf,
|
||||
@@ -585,7 +557,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -602,12 +574,7 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
(self.0)().hydrate::<FROM_SERVER>(cursor, position, extra_attrs)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
(self.0)().hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,8 +84,7 @@ mod view_implementations {
|
||||
reactive_graph::{RenderEffectState, Suspend, SuspendState},
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Position,
|
||||
PositionState, Render, RenderHtml,
|
||||
add_attr::AddAnyAttr, Position, PositionState, Render, RenderHtml,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -96,17 +95,12 @@ mod view_implementations {
|
||||
{
|
||||
type State = RenderEffectState<SuspendState<T>>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
(move || Suspend::new(async move { self.await })).build(extra_attrs)
|
||||
fn build(self) -> Self::State {
|
||||
(move || Suspend::new(async move { self.await })).build()
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
(move || Suspend::new(async move { self.await }))
|
||||
.rebuild(state, extra_attrs)
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
(move || Suspend::new(async move { self.await })).rebuild(state)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,20 +135,15 @@ mod view_implementations {
|
||||
Ser: Send + 'static,
|
||||
{
|
||||
type AsyncOutput = Option<T>;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
self.read();
|
||||
}
|
||||
|
||||
fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> impl Future<Output = Self::AsyncOutput> + Send {
|
||||
(move || Suspend::new(async move { self.await }))
|
||||
.resolve(extra_attrs)
|
||||
fn resolve(self) -> impl Future<Output = Self::AsyncOutput> + Send {
|
||||
(move || Suspend::new(async move { self.await })).resolve()
|
||||
}
|
||||
|
||||
fn to_html_with_buf(
|
||||
@@ -163,7 +152,7 @@ mod view_implementations {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
(move || Suspend::new(async move { self.await })).to_html_with_buf(
|
||||
buf,
|
||||
@@ -180,7 +169,7 @@ mod view_implementations {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -198,14 +187,9 @@ mod view_implementations {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
(move || Suspend::new(async move { self.await }))
|
||||
.hydrate::<FROM_SERVER>(cursor, position, extra_attrs)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
.hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use crate::ServerMetaContext;
|
||||
use leptos::{
|
||||
attr::{
|
||||
any_attribute::{AnyAttribute, AnyAttributeState},
|
||||
NextAttribute,
|
||||
},
|
||||
attr::{any_attribute::AnyAttribute, NextAttribute},
|
||||
component, html,
|
||||
reactive::owner::use_context,
|
||||
tachys::{
|
||||
@@ -11,8 +8,8 @@ use leptos::{
|
||||
html::attribute::Attribute,
|
||||
hydration::Cursor,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Mountable, Position,
|
||||
PositionState, Render, RenderHtml,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
},
|
||||
},
|
||||
IntoView,
|
||||
@@ -61,7 +58,6 @@ where
|
||||
At: Attribute,
|
||||
{
|
||||
attributes: At::State,
|
||||
extra_attrs: Option<Vec<AnyAttributeState>>,
|
||||
}
|
||||
|
||||
impl<At> Render for BodyView<At>
|
||||
@@ -70,27 +66,15 @@ where
|
||||
{
|
||||
type State = BodyViewState<At>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let el = document().body().expect("there to be a <body> element");
|
||||
let attributes = self.attributes.build(&el);
|
||||
let extra_attrs = extra_attrs.map(|attrs| attrs.build(&el));
|
||||
BodyViewState {
|
||||
attributes,
|
||||
extra_attrs,
|
||||
}
|
||||
|
||||
BodyViewState { attributes }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
self.attributes.rebuild(&mut state.attributes);
|
||||
if let (Some(extra_attrs), Some(extra_attr_states)) =
|
||||
(extra_attrs, &mut state.extra_attrs)
|
||||
{
|
||||
extra_attrs.rebuild(extra_attr_states);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,24 +103,17 @@ where
|
||||
At: Attribute,
|
||||
{
|
||||
type AsyncOutput = BodyView<At::AsyncOutput>;
|
||||
type Owned = BodyView<At::CloneableOwned>;
|
||||
|
||||
const MIN_LENGTH: usize = At::MIN_LENGTH;
|
||||
|
||||
fn dry_resolve(&mut self, mut extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
self.attributes.dry_resolve();
|
||||
extra_attrs.iter_mut().for_each(Attribute::dry_resolve);
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
let (attributes, _) = futures::join!(
|
||||
self.attributes.resolve(),
|
||||
ExtraAttrsMut::resolve(extra_attrs)
|
||||
);
|
||||
BodyView { attributes }
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
BodyView {
|
||||
attributes: self.attributes.resolve().await,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_html_with_buf(
|
||||
@@ -145,13 +122,12 @@ where
|
||||
_position: &mut Position,
|
||||
_escape: bool,
|
||||
_mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
if let Some(meta) = use_context::<ServerMetaContext>() {
|
||||
let mut buf = String::new();
|
||||
_ = html::attributes_to_html(
|
||||
self.attributes,
|
||||
extra_attrs,
|
||||
(self.attributes, extra_attrs),
|
||||
&mut buf,
|
||||
);
|
||||
if !buf.is_empty() {
|
||||
@@ -164,23 +140,11 @@ where
|
||||
self,
|
||||
_cursor: &Cursor,
|
||||
_position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let el = document().body().expect("there to be a <body> element");
|
||||
let attributes = self.attributes.hydrate::<FROM_SERVER>(&el);
|
||||
let extra_attrs =
|
||||
extra_attrs.map(|attrs| attrs.hydrate::<FROM_SERVER>(&el));
|
||||
|
||||
BodyViewState {
|
||||
attributes,
|
||||
extra_attrs,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
BodyView {
|
||||
attributes: self.attributes.into_cloneable_owned(),
|
||||
}
|
||||
BodyViewState { attributes }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,4 +164,11 @@ where
|
||||
fn insert_before_this(&self, _child: &mut dyn Mountable) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<leptos::tachys::renderer::types::Element> {
|
||||
vec![document()
|
||||
.body()
|
||||
.expect("there to be a <body> element")
|
||||
.into()]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use crate::ServerMetaContext;
|
||||
use leptos::{
|
||||
attr::{
|
||||
any_attribute::{AnyAttribute, AnyAttributeState},
|
||||
NextAttribute,
|
||||
},
|
||||
attr::{any_attribute::AnyAttribute, NextAttribute},
|
||||
component, html,
|
||||
reactive::owner::use_context,
|
||||
tachys::{
|
||||
@@ -11,8 +8,8 @@ use leptos::{
|
||||
html::attribute::Attribute,
|
||||
hydration::Cursor,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Mountable, Position,
|
||||
PositionState, Render, RenderHtml,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
},
|
||||
},
|
||||
IntoView,
|
||||
@@ -58,7 +55,6 @@ where
|
||||
At: Attribute,
|
||||
{
|
||||
attributes: At::State,
|
||||
extra_attrs: Option<Vec<AnyAttributeState>>,
|
||||
}
|
||||
|
||||
impl<At> Render for HtmlView<At>
|
||||
@@ -67,33 +63,18 @@ where
|
||||
{
|
||||
type State = HtmlViewState<At>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let el = document()
|
||||
.document_element()
|
||||
.expect("there to be a <html> element");
|
||||
|
||||
let attributes = self.attributes.build(&el);
|
||||
let extra_attrs = extra_attrs.map(|attrs| {
|
||||
attrs.into_iter().map(|attr| attr.build(&el)).collect()
|
||||
});
|
||||
|
||||
HtmlViewState {
|
||||
attributes,
|
||||
extra_attrs,
|
||||
}
|
||||
HtmlViewState { attributes }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
self.attributes.rebuild(&mut state.attributes);
|
||||
if let (Some(extra_attrs), Some(extra_attr_states)) =
|
||||
(extra_attrs, &mut state.extra_attrs)
|
||||
{
|
||||
extra_attrs.rebuild(extra_attr_states);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,24 +103,17 @@ where
|
||||
At: Attribute,
|
||||
{
|
||||
type AsyncOutput = HtmlView<At::AsyncOutput>;
|
||||
type Owned = HtmlView<At::CloneableOwned>;
|
||||
|
||||
const MIN_LENGTH: usize = At::MIN_LENGTH;
|
||||
|
||||
fn dry_resolve(&mut self, mut extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
self.attributes.dry_resolve();
|
||||
extra_attrs.iter_mut().for_each(Attribute::dry_resolve);
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
let (attributes, _) = futures::join!(
|
||||
self.attributes.resolve(),
|
||||
ExtraAttrsMut::resolve(extra_attrs)
|
||||
);
|
||||
HtmlView { attributes }
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
HtmlView {
|
||||
attributes: self.attributes.resolve().await,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_html_with_buf(
|
||||
@@ -148,13 +122,12 @@ where
|
||||
_position: &mut Position,
|
||||
_escape: bool,
|
||||
_mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
if let Some(meta) = use_context::<ServerMetaContext>() {
|
||||
let mut buf = String::new();
|
||||
_ = html::attributes_to_html(
|
||||
self.attributes,
|
||||
extra_attrs,
|
||||
(self.attributes, extra_attrs),
|
||||
&mut buf,
|
||||
);
|
||||
if !buf.is_empty() {
|
||||
@@ -167,30 +140,14 @@ where
|
||||
self,
|
||||
_cursor: &Cursor,
|
||||
_position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let el = document()
|
||||
.document_element()
|
||||
.expect("there to be a <html> element");
|
||||
|
||||
let attributes = self.attributes.hydrate::<FROM_SERVER>(&el);
|
||||
let extra_attrs = extra_attrs.map(|attrs| {
|
||||
attrs
|
||||
.into_iter()
|
||||
.map(|attr| attr.hydrate::<FROM_SERVER>(&el))
|
||||
.collect()
|
||||
});
|
||||
|
||||
HtmlViewState {
|
||||
attributes,
|
||||
extra_attrs,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
HtmlView {
|
||||
attributes: self.attributes.into_cloneable_owned(),
|
||||
}
|
||||
HtmlViewState { attributes }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,4 +169,10 @@ where
|
||||
fn insert_before_this(&self, _child: &mut dyn Mountable) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<leptos::tachys::renderer::types::Element> {
|
||||
vec![document()
|
||||
.document_element()
|
||||
.expect("there to be a <html> element")]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ use leptos::{
|
||||
},
|
||||
hydration::Cursor,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Mountable, Position,
|
||||
PositionState, Render, RenderHtml,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
},
|
||||
},
|
||||
IntoView,
|
||||
@@ -334,7 +334,7 @@ where
|
||||
&mut Position::NextChild,
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
_ = cx.elements.send(buf); // fails only if the receiver is already dropped
|
||||
} else {
|
||||
@@ -391,17 +391,13 @@ where
|
||||
{
|
||||
type State = RegisteredMetaTagState<E, At, Ch>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
let state = self.el.unwrap().build(extra_attrs);
|
||||
fn build(self) -> Self::State {
|
||||
let state = self.el.unwrap().build();
|
||||
RegisteredMetaTagState { state }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
self.el.unwrap().rebuild(&mut state.state, extra_attrs);
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
self.el.unwrap().rebuild(&mut state.state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,18 +430,14 @@ where
|
||||
Ch: RenderHtml + Send,
|
||||
{
|
||||
type AsyncOutput = Self;
|
||||
type Owned = RegisteredMetaTag<E, At::CloneableOwned, Ch::Owned>;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
self.el.dry_resolve(extra_attrs)
|
||||
fn dry_resolve(&mut self) {
|
||||
self.el.dry_resolve()
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self // TODO?
|
||||
}
|
||||
|
||||
@@ -455,7 +447,7 @@ where
|
||||
_position: &mut Position,
|
||||
_escape: bool,
|
||||
_mark_branches: bool,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
_extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
// meta tags are rendered into the buffer stored into the context
|
||||
// the value has already been taken out, when we're on the server
|
||||
@@ -465,7 +457,6 @@ where
|
||||
self,
|
||||
_cursor: &Cursor,
|
||||
_position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let cursor = use_context::<MetaContext>()
|
||||
.expect(
|
||||
@@ -476,16 +467,9 @@ where
|
||||
let state = self.el.unwrap().hydrate::<FROM_SERVER>(
|
||||
&cursor,
|
||||
&PositionState::new(Position::NextChild),
|
||||
extra_attrs,
|
||||
);
|
||||
RegisteredMetaTagState { state }
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
RegisteredMetaTag {
|
||||
el: self.el.map(|inner| inner.into_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, At, Ch> Mountable for RegisteredMetaTagState<E, At, Ch>
|
||||
@@ -518,6 +502,10 @@ where
|
||||
// we intended!
|
||||
false
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<leptos::tachys::renderer::types::Element> {
|
||||
self.state.elements()
|
||||
}
|
||||
}
|
||||
|
||||
/// During server rendering, inserts the meta tags that have been generated by the other components
|
||||
@@ -538,14 +526,9 @@ struct MetaTagsView;
|
||||
impl Render for MetaTagsView {
|
||||
type State = ();
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {}
|
||||
fn build(self) -> Self::State {}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
_state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
}
|
||||
fn rebuild(self, _state: &mut Self::State) {}
|
||||
}
|
||||
|
||||
impl AddAnyAttr for MetaTagsView {
|
||||
@@ -564,16 +547,12 @@ impl AddAnyAttr for MetaTagsView {
|
||||
|
||||
impl RenderHtml for MetaTagsView {
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -583,7 +562,7 @@ impl RenderHtml for MetaTagsView {
|
||||
_position: &mut Position,
|
||||
_escape: bool,
|
||||
_mark_branches: bool,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
_extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
buf.push_str("<!--HEAD-->");
|
||||
}
|
||||
@@ -592,13 +571,8 @@ impl RenderHtml for MetaTagsView {
|
||||
self,
|
||||
_cursor: &Cursor,
|
||||
_position: &PositionState,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait OrDefaultNonce {
|
||||
|
||||
@@ -11,8 +11,8 @@ use leptos::{
|
||||
dom::document,
|
||||
hydration::Cursor,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Mountable, Position,
|
||||
PositionState, Render, RenderHtml,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
},
|
||||
},
|
||||
text_prop::TextProp,
|
||||
@@ -189,7 +189,7 @@ struct TitleViewState {
|
||||
impl Render for TitleView {
|
||||
type State = TitleViewState;
|
||||
|
||||
fn build(mut self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(mut self) -> Self::State {
|
||||
let el = self.el();
|
||||
let meta = self.meta;
|
||||
if let Some(formatter) = self.formatter.take() {
|
||||
@@ -213,12 +213,8 @@ impl Render for TitleView {
|
||||
TitleViewState { effect }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
*state = self.build(extra_attrs);
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
*state = self.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,16 +234,12 @@ impl AddAnyAttr for TitleView {
|
||||
|
||||
impl RenderHtml for TitleView {
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -257,7 +249,7 @@ impl RenderHtml for TitleView {
|
||||
_position: &mut Position,
|
||||
_escape: bool,
|
||||
_mark_branches: bool,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
_extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
// meta tags are rendered into the buffer stored into the context
|
||||
// the value has already been taken out, when we're on the server
|
||||
@@ -267,7 +259,6 @@ impl RenderHtml for TitleView {
|
||||
mut self,
|
||||
_cursor: &Cursor,
|
||||
_position: &PositionState,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let el = self.el();
|
||||
let meta = self.meta;
|
||||
@@ -292,10 +283,6 @@ impl RenderHtml for TitleView {
|
||||
});
|
||||
TitleViewState { effect }
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Mountable for TitleViewState {
|
||||
@@ -313,4 +300,8 @@ impl Mountable for TitleViewState {
|
||||
fn insert_before_this(&self, _child: &mut dyn Mountable) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<leptos::tachys::renderer::types::Element> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ use tachys::{
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr,
|
||||
any_view::{AnyView, AnyViewState, ExtraAttrsMut, IntoAny},
|
||||
any_view::{AnyView, AnyViewState, IntoAny},
|
||||
Mountable, Position, PositionState, Render, RenderHtml,
|
||||
},
|
||||
};
|
||||
@@ -69,6 +69,10 @@ impl Mountable for FlatRoutesViewState {
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.view.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<tachys::renderer::types::Element> {
|
||||
self.view.elements()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Loc, Defs, FalFn, Fal> Render for FlatRoutesView<Loc, Defs, FalFn>
|
||||
@@ -80,7 +84,7 @@ where
|
||||
{
|
||||
type State = Rc<RefCell<FlatRoutesViewState>>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let FlatRoutesView {
|
||||
current_url,
|
||||
routes,
|
||||
@@ -118,7 +122,7 @@ where
|
||||
|
||||
match new_match {
|
||||
None => Rc::new(RefCell::new(FlatRoutesViewState {
|
||||
view: fallback().into_any().build(extra_attrs),
|
||||
view: fallback().into_any().build(),
|
||||
id,
|
||||
owner,
|
||||
params,
|
||||
@@ -151,7 +155,7 @@ where
|
||||
|
||||
match view.as_mut().now_or_never() {
|
||||
Some(view) => Rc::new(RefCell::new(FlatRoutesViewState {
|
||||
view: view.into_any().build(extra_attrs),
|
||||
view: view.into_any().build(),
|
||||
id,
|
||||
owner,
|
||||
params,
|
||||
@@ -162,7 +166,7 @@ where
|
||||
None => {
|
||||
let state =
|
||||
Rc::new(RefCell::new(FlatRoutesViewState {
|
||||
view: ().into_any().build(extra_attrs.clone()),
|
||||
view: ().into_any().build(),
|
||||
id,
|
||||
owner,
|
||||
params,
|
||||
@@ -175,10 +179,8 @@ where
|
||||
let state = Rc::clone(&state);
|
||||
async move {
|
||||
let view = view.await;
|
||||
view.into_any().rebuild(
|
||||
&mut state.borrow_mut().view,
|
||||
extra_attrs,
|
||||
);
|
||||
view.into_any()
|
||||
.rebuild(&mut state.borrow_mut().view);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -189,11 +191,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let FlatRoutesView {
|
||||
current_url,
|
||||
location,
|
||||
@@ -271,9 +269,7 @@ where
|
||||
provide_context(url);
|
||||
provide_context(params_memo);
|
||||
provide_context(Matched(ArcMemo::from(new_matched)));
|
||||
fallback()
|
||||
.into_any()
|
||||
.rebuild(&mut state.borrow_mut().view, extra_attrs)
|
||||
fallback().into_any().rebuild(&mut state.borrow_mut().view)
|
||||
});
|
||||
if let Some(location) = location {
|
||||
location.ready_to_complete();
|
||||
@@ -323,10 +319,8 @@ where
|
||||
== spawned_path
|
||||
{
|
||||
let rebuild = move || {
|
||||
view.into_any().rebuild(
|
||||
&mut state.borrow_mut().view,
|
||||
extra_attrs,
|
||||
);
|
||||
view.into_any()
|
||||
.rebuild(&mut state.borrow_mut().view);
|
||||
};
|
||||
if transition {
|
||||
start_view_transition(0, is_back, rebuild);
|
||||
@@ -354,7 +348,7 @@ impl<Loc, Defs, FalFn, Fal> AddAnyAttr for FlatRoutesView<Loc, Defs, FalFn>
|
||||
where
|
||||
Loc: LocationProvider + Send,
|
||||
Defs: MatchNestedRoutes + Send + 'static,
|
||||
FalFn: FnOnce() -> Fal + Send + 'static,
|
||||
FalFn: FnOnce() -> Fal + Send,
|
||||
Fal: RenderHtml + 'static,
|
||||
{
|
||||
type Output<SomeNewAttr: leptos::attr::Attribute> =
|
||||
@@ -427,20 +421,16 @@ impl<Loc, Defs, FalFn, Fal> RenderHtml for FlatRoutesView<Loc, Defs, FalFn>
|
||||
where
|
||||
Loc: LocationProvider + Send,
|
||||
Defs: MatchNestedRoutes + Send + 'static,
|
||||
FalFn: FnOnce() -> Fal + Send + 'static,
|
||||
FalFn: FnOnce() -> Fal + Send,
|
||||
Fal: RenderHtml + 'static,
|
||||
{
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = <Either<Fal, AnyView> as RenderHtml>::MIN_LENGTH;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -450,7 +440,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
// if this is being run on the server for the first time, generating all possible routes
|
||||
if RouteList::is_generating() {
|
||||
@@ -513,7 +503,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -531,7 +521,6 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
// this can be mostly the same as the build() implementation, but with hydrate()
|
||||
//
|
||||
@@ -576,11 +565,9 @@ where
|
||||
|
||||
match new_match {
|
||||
None => Rc::new(RefCell::new(FlatRoutesViewState {
|
||||
view: fallback().into_any().hydrate::<FROM_SERVER>(
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs,
|
||||
),
|
||||
view: fallback()
|
||||
.into_any()
|
||||
.hydrate::<FROM_SERVER>(cursor, position),
|
||||
id,
|
||||
owner,
|
||||
params,
|
||||
@@ -613,11 +600,9 @@ where
|
||||
|
||||
match view.as_mut().now_or_never() {
|
||||
Some(view) => Rc::new(RefCell::new(FlatRoutesViewState {
|
||||
view: view.into_any().hydrate::<FROM_SERVER>(
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs,
|
||||
),
|
||||
view: view
|
||||
.into_any()
|
||||
.hydrate::<FROM_SERVER>(cursor, position),
|
||||
id,
|
||||
owner,
|
||||
params,
|
||||
@@ -633,8 +618,4 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ use tachys::{
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr,
|
||||
any_view::{AnyView, ExtraAttrsMut, IntoAny},
|
||||
any_view::{AnyView, IntoAny},
|
||||
either::EitherOf3State,
|
||||
Mountable, Position, PositionState, Render, RenderHtml,
|
||||
},
|
||||
@@ -76,7 +76,7 @@ where
|
||||
// TODO support fallback while loading
|
||||
type State = NestedRouteViewState<Fal>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let NestedRoutesView {
|
||||
routes,
|
||||
outer_owner,
|
||||
@@ -95,7 +95,7 @@ where
|
||||
let new_match = routes.match_route(url.path());
|
||||
|
||||
// start with an empty view because we'll be loading routes async
|
||||
let view = EitherOf3::A(()).build(extra_attrs.clone());
|
||||
let view = EitherOf3::A(()).build();
|
||||
let view = Rc::new(RefCell::new(view));
|
||||
let matched_view = match new_match {
|
||||
None => EitherOf3::B(fallback()),
|
||||
@@ -120,7 +120,7 @@ where
|
||||
for trigger in triggers {
|
||||
trigger.notify();
|
||||
}
|
||||
matched_view.rebuild(&mut *view.borrow_mut(), extra_attrs);
|
||||
matched_view.rebuild(&mut *view.borrow_mut());
|
||||
})
|
||||
});
|
||||
|
||||
@@ -132,11 +132,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let url_snapshot = self.current_url.get_untracked();
|
||||
|
||||
// if the path is the same, we do not need to re-route
|
||||
@@ -158,7 +154,7 @@ where
|
||||
match new_match {
|
||||
None => {
|
||||
EitherOf3::<(), Fal, AnyView>::B((self.fallback)())
|
||||
.rebuild(&mut state.view.borrow_mut(), extra_attrs);
|
||||
.rebuild(&mut state.view.borrow_mut());
|
||||
state.outlets.clear();
|
||||
if let Some(loc) = self.location {
|
||||
loc.ready_to_complete();
|
||||
@@ -217,10 +213,7 @@ where
|
||||
if matches!(state.view.borrow().state, EitherOf3::B(_)) {
|
||||
self.outer_owner.with(|| {
|
||||
EitherOf3::<(), Fal, AnyView>::C(Outlet().into_any())
|
||||
.rebuild(
|
||||
&mut *state.view.borrow_mut(),
|
||||
extra_attrs,
|
||||
);
|
||||
.rebuild(&mut *state.view.borrow_mut());
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -235,8 +228,8 @@ where
|
||||
impl<Loc, Defs, Fal, FalFn> AddAnyAttr for NestedRoutesView<Loc, Defs, FalFn>
|
||||
where
|
||||
Loc: LocationProvider + Send,
|
||||
Defs: MatchNestedRoutes + Send + 'static,
|
||||
FalFn: FnOnce() -> Fal + Send + 'static,
|
||||
Defs: MatchNestedRoutes + Send,
|
||||
FalFn: FnOnce() -> Fal + Send,
|
||||
Fal: RenderHtml + 'static,
|
||||
{
|
||||
type Output<SomeNewAttr: leptos::attr::Attribute> =
|
||||
@@ -256,21 +249,17 @@ where
|
||||
impl<Loc, Defs, FalFn, Fal> RenderHtml for NestedRoutesView<Loc, Defs, FalFn>
|
||||
where
|
||||
Loc: LocationProvider + Send,
|
||||
Defs: MatchNestedRoutes + Send + 'static,
|
||||
FalFn: FnOnce() -> Fal + Send + 'static,
|
||||
Defs: MatchNestedRoutes + Send,
|
||||
FalFn: FnOnce() -> Fal + Send,
|
||||
Fal: RenderHtml + 'static,
|
||||
{
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = 0; // TODO
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -280,7 +269,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
// if this is being run on the server for the first time, generating all possible routes
|
||||
if RouteList::is_generating() {
|
||||
@@ -376,7 +365,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -427,7 +416,6 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let NestedRoutesView {
|
||||
routes,
|
||||
@@ -467,7 +455,7 @@ where
|
||||
outer_owner.with(|| EitherOf3::C(Outlet().into_any()))
|
||||
}
|
||||
}
|
||||
.hydrate::<FROM_SERVER>(cursor, position, extra_attrs),
|
||||
.hydrate::<FROM_SERVER>(cursor, position),
|
||||
));
|
||||
|
||||
NestedRouteViewState {
|
||||
@@ -477,10 +465,6 @@ where
|
||||
view,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
type OutletViewFn = Box<dyn Fn() -> Suspend<AnyView> + Send>;
|
||||
@@ -897,6 +881,10 @@ where
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.view.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<tachys::renderer::types::Element> {
|
||||
self.view.elements()
|
||||
}
|
||||
}
|
||||
|
||||
/// Displays the child route nested in a parent route, allowing you to control exactly where
|
||||
|
||||
@@ -89,7 +89,7 @@ where
|
||||
type State =
|
||||
ReactiveRouterInnerState<Rndr, Loc, Defs, FallbackFn, Fallback>;
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let (prev_id, inner) = self.inner.fallback_or_view();
|
||||
let owner = self.owner.with(Owner::new);
|
||||
ReactiveRouterInnerState {
|
||||
@@ -100,11 +100,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let (new_id, view) = self.inner.fallback_or_view();
|
||||
if new_id != state.prev_id {
|
||||
state.owner = self.owner.with(Owner::new)
|
||||
@@ -133,9 +129,7 @@ where
|
||||
buf: &mut String,
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
mark_branches: bool, extra_attrs: Vec<AnyAttribute>) {
|
||||
// if this is being run on the server for the first time, generating all possible routes
|
||||
if RouteList::is_generating() {
|
||||
let mut routes = RouteList::new();
|
||||
@@ -160,9 +154,7 @@ where
|
||||
buf: &mut StreamBuilder,
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) where
|
||||
mark_branches: bool, extra_attrs: Vec<AnyAttribute>) where
|
||||
Self: Sized,
|
||||
{
|
||||
self.inner
|
||||
@@ -175,7 +167,6 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let (prev_id, inner) = self.inner.fallback_or_view();
|
||||
let owner = self.owner.with(Owner::new);
|
||||
@@ -287,7 +278,7 @@ where
|
||||
{
|
||||
type State = ReactiveRouteState<View::State>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let MatchedRoute {
|
||||
search_params,
|
||||
params,
|
||||
@@ -298,19 +289,14 @@ where
|
||||
params: ArcRwSignal::new(params),
|
||||
matched: ArcRwSignal::new(matched),
|
||||
};
|
||||
let view_state =
|
||||
untrack(|| (self.view_fn)(&matched).build(extra_attrs.clone()));
|
||||
let view_state = untrack(|| (self.view_fn)(&matched).build());
|
||||
ReactiveRouteState {
|
||||
matched,
|
||||
view_state,
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
mut self,
|
||||
state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(mut self, state: &mut Self::State) {
|
||||
let ReactiveRouteState { matched, .. } = state;
|
||||
matched
|
||||
.search_params
|
||||
@@ -335,9 +321,7 @@ where
|
||||
buf: &mut String,
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
mark_branches: bool, extra_attrs: Vec<AnyAttribute>) {
|
||||
let MatchedRoute {
|
||||
search_params,
|
||||
params,
|
||||
@@ -349,12 +333,7 @@ where
|
||||
matched: ArcRwSignal::new(matched),
|
||||
};
|
||||
untrack(|| {
|
||||
(self.view_fn)(&matched).to_html_with_buf(
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
extra_attrs.clone(),
|
||||
)
|
||||
(self.view_fn)(&matched).to_html_with_buf(buf, position, escape)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -363,9 +342,7 @@ where
|
||||
buf: &mut StreamBuilder,
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) where
|
||||
mark_branches: bool, extra_attrs: Vec<AnyAttribute>) where
|
||||
Self: Sized,
|
||||
{
|
||||
let MatchedRoute {
|
||||
@@ -379,12 +356,8 @@ where
|
||||
matched: ArcRwSignal::new(matched),
|
||||
};
|
||||
untrack(|| {
|
||||
(self.view_fn)(&matched).to_html_async_with_buf::<OUT_OF_ORDER>(
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
extra_attrs.clone(),
|
||||
)
|
||||
(self.view_fn)(&matched)
|
||||
.to_html_async_with_buf::<OUT_OF_ORDER>(buf, position, escape)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -392,7 +365,6 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let MatchedRoute {
|
||||
search_params,
|
||||
@@ -405,11 +377,7 @@ where
|
||||
matched: ArcRwSignal::new(matched),
|
||||
};
|
||||
let view_state = untrack(|| {
|
||||
(self.view_fn)(&matched).hydrate::<FROM_SERVER>(
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs.clone(),
|
||||
)
|
||||
(self.view_fn)(&matched).hydrate::<FROM_SERVER>(cursor, position)
|
||||
});
|
||||
ReactiveRouteState {
|
||||
matched,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#![allow(unused_mut)]
|
||||
use super::{Attribute, NextAttribute};
|
||||
use dyn_clone::DynClone;
|
||||
use std::{
|
||||
@@ -36,10 +35,6 @@ pub struct AnyAttribute {
|
||||
type_id: TypeId,
|
||||
html_len: usize,
|
||||
value: Box<dyn DynAttr>,
|
||||
|
||||
/// Temporary attribute set during the resolving cycle, to resolve only once.
|
||||
pub(crate) resolved: bool,
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
to_html: fn(
|
||||
Box<dyn DynAttr>,
|
||||
@@ -202,7 +197,6 @@ where
|
||||
type_id: TypeId::of::<T::CloneableOwned>(),
|
||||
html_len: value.html_len(),
|
||||
value,
|
||||
resolved: false,
|
||||
#[cfg(feature = "ssr")]
|
||||
to_html,
|
||||
build,
|
||||
@@ -309,13 +303,10 @@ impl Attribute for AnyAttribute {
|
||||
);
|
||||
}
|
||||
|
||||
async fn resolve(mut self) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
#[cfg(feature = "ssr")]
|
||||
{
|
||||
let res = (self.resolve)(self.value).await;
|
||||
// Used by batch_resolve_items_with_extra_attrs() for optimisations.
|
||||
self.resolved = true;
|
||||
res
|
||||
(self.resolve)(self.value).await
|
||||
}
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
panic!(
|
||||
|
||||
@@ -24,7 +24,7 @@ use web_sys::Element;
|
||||
/// let view = element.on(ev::click, move |_| /* ... */);
|
||||
///
|
||||
/// // `element` now contains the actual element
|
||||
/// let element = element.build(None);
|
||||
/// let element = element.build();
|
||||
/// let remove = element.on(ev::blur, move |_| /* ... */);
|
||||
/// ```
|
||||
pub trait ElementExt {
|
||||
|
||||
@@ -3,17 +3,18 @@ use crate::hydration::set_currently_hydrating;
|
||||
use crate::{
|
||||
html::attribute::Attribute,
|
||||
hydration::{failed_to_cast_element, Cursor},
|
||||
prelude::IntoAttribute,
|
||||
renderer::{CastFrom, Rndr},
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, IntoRender, Mountable,
|
||||
Position, PositionState, Render, RenderHtml, ToTemplate,
|
||||
add_attr::AddAnyAttr, IntoRender, Mountable, Position, PositionState,
|
||||
Render, RenderHtml, ToTemplate,
|
||||
},
|
||||
};
|
||||
use const_str_slice_concat::{
|
||||
const_concat, const_concat_with_prefix, str_from_buffer,
|
||||
};
|
||||
use futures::future::join3;
|
||||
use futures::future::join;
|
||||
use next_tuple::NextTuple;
|
||||
use std::ops::Deref;
|
||||
|
||||
@@ -22,8 +23,7 @@ mod element_ext;
|
||||
mod elements;
|
||||
mod inner_html;
|
||||
use super::attribute::{
|
||||
any_attribute::{AnyAttribute, AnyAttributeState},
|
||||
escape_attr, NextAttribute,
|
||||
any_attribute::AnyAttribute, escape_attr, NextAttribute,
|
||||
};
|
||||
pub use custom::*;
|
||||
pub use element_ext::*;
|
||||
@@ -186,42 +186,31 @@ where
|
||||
{
|
||||
type State = ElementState<At::State, Ch::State>;
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let ElementState {
|
||||
attrs, children, ..
|
||||
} = state;
|
||||
self.attributes.rebuild(attrs);
|
||||
if let (Some(extra_attrs), Some(extra_attr_states)) =
|
||||
(extra_attrs, &mut state.extra_attrs)
|
||||
{
|
||||
extra_attrs.rebuild(extra_attr_states);
|
||||
}
|
||||
if let Some(children) = children {
|
||||
self.children.rebuild(children, None);
|
||||
self.children.rebuild(children);
|
||||
}
|
||||
}
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let el = Rndr::create_element(self.tag.tag(), E::NAMESPACE);
|
||||
|
||||
let attrs = self.attributes.build(&el);
|
||||
let extra_attrs = extra_attrs.map(|attrs| attrs.build(&el));
|
||||
let children = if E::SELF_CLOSING {
|
||||
None
|
||||
} else {
|
||||
let mut children = self.children.build(None);
|
||||
let mut children = self.children.build();
|
||||
children.mount(&el, None);
|
||||
Some(children)
|
||||
};
|
||||
ElementState {
|
||||
el,
|
||||
children,
|
||||
attrs,
|
||||
extra_attrs,
|
||||
children,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,7 +222,6 @@ where
|
||||
Ch: RenderHtml + Send,
|
||||
{
|
||||
type AsyncOutput = HtmlElement<E, At::AsyncOutput, Ch::AsyncOutput>;
|
||||
type Owned = HtmlElement<E, At::CloneableOwned, Ch::Owned>;
|
||||
|
||||
const MIN_LENGTH: usize = if E::SELF_CLOSING {
|
||||
3 // < ... />
|
||||
@@ -248,22 +236,14 @@ where
|
||||
+ E::TAG.len()
|
||||
};
|
||||
|
||||
fn dry_resolve(&mut self, mut extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
self.attributes.dry_resolve();
|
||||
extra_attrs.iter_mut().for_each(Attribute::dry_resolve);
|
||||
self.children.dry_resolve(ExtraAttrsMut::default());
|
||||
self.children.dry_resolve();
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
let (attributes, _, children) = join3(
|
||||
self.attributes.resolve(),
|
||||
ExtraAttrsMut::resolve(extra_attrs),
|
||||
self.children.resolve(ExtraAttrsMut::default()),
|
||||
)
|
||||
.await;
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
let (attributes, children) =
|
||||
join(self.attributes.resolve(), self.children.resolve()).await;
|
||||
HtmlElement {
|
||||
#[cfg(any(debug_assertions, leptos_debuginfo))]
|
||||
defined_at: self.defined_at,
|
||||
@@ -273,7 +253,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn html_len(&self, extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
if E::SELF_CLOSING {
|
||||
3 // < ... />
|
||||
+ E::TAG.len()
|
||||
@@ -282,10 +262,7 @@ where
|
||||
2 // < ... >
|
||||
+ E::TAG.len()
|
||||
+ self.attributes.html_len()
|
||||
+ extra_attrs.map(|attrs| {
|
||||
attrs.into_iter().map(Attribute::html_len).sum::<usize>()
|
||||
}).unwrap_or(0)
|
||||
+ self.children.html_len(None)
|
||||
+ self.children.html_len()
|
||||
+ 3 // </ ... >
|
||||
+ E::TAG.len()
|
||||
}
|
||||
@@ -297,13 +274,14 @@ where
|
||||
position: &mut Position,
|
||||
_escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attributes: Vec<AnyAttribute>,
|
||||
) {
|
||||
// opening tag
|
||||
buf.push('<');
|
||||
buf.push_str(self.tag.tag());
|
||||
|
||||
let inner_html = attributes_to_html(self.attributes, extra_attrs, buf);
|
||||
let inner_html =
|
||||
attributes_to_html((self.attributes, extra_attributes), buf);
|
||||
|
||||
buf.push('>');
|
||||
|
||||
@@ -318,7 +296,7 @@ where
|
||||
position,
|
||||
E::ESCAPE_CHILDREN,
|
||||
mark_branches,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -336,7 +314,7 @@ where
|
||||
position: &mut Position,
|
||||
_escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attributes: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -346,7 +324,7 @@ where
|
||||
buf.push_str(self.tag.tag());
|
||||
|
||||
let inner_html =
|
||||
attributes_to_html(self.attributes, extra_attrs, &mut buf);
|
||||
attributes_to_html((self.attributes, extra_attributes), &mut buf);
|
||||
|
||||
buf.push('>');
|
||||
buffer.push_sync(&buf);
|
||||
@@ -362,7 +340,7 @@ where
|
||||
position,
|
||||
E::ESCAPE_CHILDREN,
|
||||
mark_branches,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -380,7 +358,6 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
#[cfg(any(debug_assertions, leptos_debuginfo))]
|
||||
{
|
||||
@@ -405,15 +382,13 @@ where
|
||||
});
|
||||
|
||||
let attrs = self.attributes.hydrate::<FROM_SERVER>(&el);
|
||||
let extra_attrs = extra_attrs
|
||||
.map(|attrs| Attribute::hydrate::<FROM_SERVER>(attrs, &el));
|
||||
|
||||
// hydrate children
|
||||
let children = if !Ch::EXISTS || !E::ESCAPE_CHILDREN {
|
||||
None
|
||||
} else {
|
||||
position.set(Position::FirstChild);
|
||||
Some(self.children.hydrate::<FROM_SERVER>(cursor, position, None))
|
||||
Some(self.children.hydrate::<FROM_SERVER>(cursor, position))
|
||||
};
|
||||
|
||||
// go to next sibling
|
||||
@@ -427,32 +402,19 @@ where
|
||||
|
||||
ElementState {
|
||||
el,
|
||||
children,
|
||||
attrs,
|
||||
extra_attrs,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
HtmlElement {
|
||||
#[cfg(any(debug_assertions, leptos_debuginfo))]
|
||||
defined_at: self.defined_at,
|
||||
tag: self.tag,
|
||||
attributes: self.attributes.into_cloneable_owned(),
|
||||
children: self.children.into_owned(),
|
||||
children,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders an [`Attribute`] (which can be one or more HTML attributes) into an HTML buffer.
|
||||
pub fn attributes_to_html<At>(
|
||||
attr: At,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
buf: &mut String,
|
||||
) -> String
|
||||
pub fn attributes_to_html<At>(attr: At, buf: &mut String) -> String
|
||||
where
|
||||
At: Attribute,
|
||||
At: IntoAttribute,
|
||||
{
|
||||
let attr = attr.into_attr();
|
||||
|
||||
// `class` and `style` are created first, and pushed later
|
||||
// this is because they can be filled by a mixture of values that include
|
||||
// either the whole value (`class="..."` or `style="..."`) and individual
|
||||
@@ -468,11 +430,6 @@ where
|
||||
|
||||
// inject regular attributes, and fill class and style
|
||||
attr.to_html(buf, &mut class, &mut style, &mut inner_html);
|
||||
if let Some(extra_attrs) = extra_attrs {
|
||||
for attr in extra_attrs {
|
||||
attr.to_html(buf, &mut class, &mut style, &mut inner_html);
|
||||
}
|
||||
}
|
||||
|
||||
if !class.is_empty() {
|
||||
buf.push(' ');
|
||||
@@ -493,10 +450,8 @@ where
|
||||
/// The retained view state for an HTML element.
|
||||
pub struct ElementState<At, Ch> {
|
||||
pub(crate) el: crate::renderer::types::Element,
|
||||
pub(crate) attrs: At,
|
||||
pub(crate) children: Option<Ch>,
|
||||
|
||||
attrs: At,
|
||||
extra_attrs: Option<Vec<AnyAttributeState>>,
|
||||
}
|
||||
|
||||
impl<At, Ch> Deref for ElementState<At, Ch> {
|
||||
@@ -531,6 +486,10 @@ impl<At, Ch> Mountable for ElementState<At, Ch> {
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![self.el.clone()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, At, Ch> ToTemplate for HtmlElement<E, At, Ch>
|
||||
@@ -639,7 +598,7 @@ mod tests {
|
||||
fn mock_dom_creates_element() {
|
||||
let el: HtmlElement<Main, _, _, MockDom> =
|
||||
main().child(p().id("test").lang("en").child("Hello, world!"));
|
||||
let el = el.build(None);
|
||||
let el = el.build();
|
||||
assert_eq!(
|
||||
el.el.to_debug_html(),
|
||||
"<main><p id=\"test\" lang=\"en\">Hello, world!</p></main>"
|
||||
@@ -653,7 +612,7 @@ mod tests {
|
||||
em().child("beautiful"),
|
||||
" world!",
|
||||
)));
|
||||
let el = el.build(None);
|
||||
let el = el.build();
|
||||
assert_eq!(
|
||||
el.el.to_debug_html(),
|
||||
"<main><p>Hello, <em>beautiful</em> world!</p></main>"
|
||||
|
||||
@@ -3,9 +3,7 @@ use crate::{
|
||||
hydration::Cursor,
|
||||
prelude::{Render, RenderHtml},
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Position, PositionState,
|
||||
},
|
||||
view::{add_attr::AddAnyAttr, Position, PositionState},
|
||||
};
|
||||
|
||||
/// An island of interactivity in an otherwise-inert HTML document.
|
||||
@@ -61,16 +59,12 @@ where
|
||||
{
|
||||
type State = View::State;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
self.view.build(extra_attrs)
|
||||
fn build(self) -> Self::State {
|
||||
self.view.build()
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
self.view.rebuild(state, extra_attrs);
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
self.view.rebuild(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +100,6 @@ where
|
||||
View: RenderHtml,
|
||||
{
|
||||
type AsyncOutput = Island<View::AsyncOutput>;
|
||||
type Owned = Island<View::Owned>;
|
||||
|
||||
const MIN_LENGTH: usize = ISLAND_TAG.len() * 2
|
||||
+ "<>".len()
|
||||
@@ -114,14 +107,11 @@ where
|
||||
+ "data-component".len()
|
||||
+ View::MIN_LENGTH;
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
self.view.dry_resolve(extra_attrs)
|
||||
fn dry_resolve(&mut self) {
|
||||
self.view.dry_resolve()
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
let Island {
|
||||
component,
|
||||
props_json,
|
||||
@@ -130,7 +120,7 @@ where
|
||||
Island {
|
||||
component,
|
||||
props_json,
|
||||
view: view.resolve(extra_attrs).await,
|
||||
view: view.resolve().await,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +130,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
Self::open_tag(self.component, &self.props_json, buf);
|
||||
self.view.to_html_with_buf(
|
||||
@@ -159,7 +149,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -187,7 +177,6 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
if position.get() == Position::FirstChild {
|
||||
cursor.child();
|
||||
@@ -196,16 +185,7 @@ where
|
||||
}
|
||||
position.set(Position::FirstChild);
|
||||
|
||||
self.view
|
||||
.hydrate::<FROM_SERVER>(cursor, position, extra_attrs)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
Island {
|
||||
component: self.component,
|
||||
props_json: self.props_json,
|
||||
view: self.view.into_owned(),
|
||||
}
|
||||
self.view.hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,14 +235,9 @@ where
|
||||
{
|
||||
type State = ();
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {}
|
||||
fn build(self) -> Self::State {}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
_state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
}
|
||||
fn rebuild(self, _state: &mut Self::State) {}
|
||||
}
|
||||
|
||||
impl<View> AddAnyAttr for IslandChildren<View>
|
||||
@@ -292,24 +267,20 @@ where
|
||||
View: RenderHtml,
|
||||
{
|
||||
type AsyncOutput = IslandChildren<View::AsyncOutput>;
|
||||
type Owned = IslandChildren<View::Owned>;
|
||||
|
||||
const MIN_LENGTH: usize = ISLAND_CHILDREN_TAG.len() * 2
|
||||
+ "<>".len()
|
||||
+ "</>".len()
|
||||
+ View::MIN_LENGTH;
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
self.view.dry_resolve(extra_attrs)
|
||||
fn dry_resolve(&mut self) {
|
||||
self.view.dry_resolve()
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
let IslandChildren { view, on_hydrate } = self;
|
||||
IslandChildren {
|
||||
view: view.resolve(extra_attrs).await,
|
||||
view: view.resolve().await,
|
||||
on_hydrate,
|
||||
}
|
||||
}
|
||||
@@ -320,7 +291,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
Self::open_tag(buf);
|
||||
self.view.to_html_with_buf(
|
||||
@@ -339,7 +310,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -367,7 +338,6 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
// island children aren't hydrated
|
||||
// we update the walk to pass over them
|
||||
@@ -402,11 +372,4 @@ where
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
IslandChildren {
|
||||
view: self.view.into_owned(),
|
||||
on_hydrate: self.on_hydrate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@ use crate::{
|
||||
dom::{Element, Node},
|
||||
CastFrom, Rndr,
|
||||
},
|
||||
view::{
|
||||
any_view::ExtraAttrsMut, Position, PositionState, Render, RenderHtml,
|
||||
},
|
||||
view::{Position, PositionState, Render, RenderHtml},
|
||||
};
|
||||
use attribute::any_attribute::AnyAttribute;
|
||||
use std::borrow::Cow;
|
||||
@@ -46,30 +44,21 @@ pub fn doctype(value: &'static str) -> Doctype {
|
||||
impl Render for Doctype {
|
||||
type State = ();
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {}
|
||||
fn build(self) -> Self::State {}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
_state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
}
|
||||
fn rebuild(self, _state: &mut Self::State) {}
|
||||
}
|
||||
|
||||
no_attrs!(Doctype);
|
||||
|
||||
impl RenderHtml for Doctype {
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = "<!DOCTYPE html>".len();
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -79,7 +68,7 @@ impl RenderHtml for Doctype {
|
||||
_position: &mut Position,
|
||||
_escape: bool,
|
||||
_mark_branches: bool,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
_extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
buf.push_str("<!DOCTYPE ");
|
||||
buf.push_str(self.value);
|
||||
@@ -90,13 +79,8 @@ impl RenderHtml for Doctype {
|
||||
self,
|
||||
_cursor: &Cursor,
|
||||
_position: &PositionState,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// An element that contains no interactivity, and whose contents can be known at compile time.
|
||||
@@ -126,21 +110,21 @@ impl Mountable for InertElementState {
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.1.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![self.1.clone()]
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for InertElement {
|
||||
type State = InertElementState;
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let el = Rndr::create_element_from_html(&self.html);
|
||||
InertElementState(self.html, el)
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let InertElementState(prev, el) = state;
|
||||
if &self.html != prev {
|
||||
let mut new_el = Rndr::create_element_from_html(&self.html);
|
||||
@@ -171,17 +155,16 @@ impl AddAnyAttr for InertElement {
|
||||
|
||||
impl RenderHtml for InertElement {
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn html_len(&self, _extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
self.html.len()
|
||||
}
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(self, _extra_attrs: ExtraAttrsMut<'_>) -> Self {
|
||||
async fn resolve(self) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -191,7 +174,7 @@ impl RenderHtml for InertElement {
|
||||
position: &mut Position,
|
||||
_escape: bool,
|
||||
_mark_branches: bool,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
_extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
buf.push_str(&self.html);
|
||||
*position = Position::NextChild;
|
||||
@@ -201,7 +184,6 @@ impl RenderHtml for InertElement {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let curr_position = position.get();
|
||||
if curr_position == Position::FirstChild {
|
||||
@@ -214,8 +196,4 @@ impl RenderHtml for InertElement {
|
||||
position.set(Position::NextChild);
|
||||
InertElementState(self.html, el)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@ use crate::{
|
||||
no_attrs,
|
||||
prelude::{Mountable, Render, RenderHtml},
|
||||
renderer::Rndr,
|
||||
view::{
|
||||
any_view::ExtraAttrsMut, strings::StrState, Position, PositionState,
|
||||
ToTemplate,
|
||||
},
|
||||
view::{strings::StrState, Position, PositionState, ToTemplate},
|
||||
};
|
||||
use oco_ref::Oco;
|
||||
|
||||
@@ -24,16 +21,12 @@ pub struct OcoStrState {
|
||||
impl Render for Oco<'static, str> {
|
||||
type State = OcoStrState;
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let node = Rndr::create_text_node(&self);
|
||||
OcoStrState { node, str: self }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let OcoStrState { node, str } = state;
|
||||
if &self != str {
|
||||
Rndr::set_text(node, &self);
|
||||
@@ -46,16 +39,12 @@ no_attrs!(Oco<'static, str>);
|
||||
|
||||
impl RenderHtml for Oco<'static, str> {
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -65,7 +54,7 @@ impl RenderHtml for Oco<'static, str> {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
<&str as RenderHtml>::to_html_with_buf(
|
||||
&self,
|
||||
@@ -81,21 +70,13 @@ impl RenderHtml for Oco<'static, str> {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let this: &str = self.as_ref();
|
||||
let StrState { node, .. } = <&str as RenderHtml>::hydrate::<FROM_SERVER>(
|
||||
this,
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs,
|
||||
this, cursor, position,
|
||||
);
|
||||
OcoStrState { node, str: self }
|
||||
}
|
||||
|
||||
fn into_owned(self) -> <Self as RenderHtml>::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTemplate for Oco<'static, str> {
|
||||
@@ -130,6 +111,10 @@ impl Mountable for OcoStrState {
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.node.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl AttributeValue for Oco<'static, str> {
|
||||
|
||||
@@ -352,7 +352,7 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, _extra_attrs: Option<Vec<AnyAttribute>>) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let (names, mut f) = self;
|
||||
let prev_value = state.take_value();
|
||||
|
||||
@@ -433,7 +433,7 @@ where
|
||||
<String as IntoClass>::build(self.deref().to_owned(), el)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, _extra_attrs: Option<Vec<AnyAttribute>>) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
<String as IntoClass>::rebuild(self.deref().to_owned(), state)
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ where
|
||||
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -489,7 +489,7 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, _extra_attrs: Option<Vec<AnyAttribute>>) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
<(&'static str, bool) as IntoClass>::rebuild(
|
||||
(self.0, *self.1.deref()),
|
||||
state,
|
||||
@@ -506,7 +506,7 @@ where
|
||||
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -901,7 +901,7 @@ where
|
||||
state
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, _extra_attrs: Option<Vec<AnyAttribute>>) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
reactive_graph::spawn_local_scoped({
|
||||
let state = Rc::clone(state);
|
||||
async move {
|
||||
@@ -925,7 +925,7 @@ where
|
||||
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self.inner.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ use crate::{
|
||||
renderer::Rndr,
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Mountable, Position,
|
||||
PositionState, Render, RenderHtml, ToTemplate,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml, ToTemplate,
|
||||
},
|
||||
};
|
||||
use reactive_graph::effect::RenderEffect;
|
||||
@@ -57,7 +57,7 @@ where
|
||||
type State = RenderEffectState<V::State>;
|
||||
|
||||
#[track_caller]
|
||||
fn build(mut self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(mut self) -> Self::State {
|
||||
let hook = throw_error::get_error_hook();
|
||||
RenderEffect::new(move |prev| {
|
||||
let _guard = hook
|
||||
@@ -65,22 +65,18 @@ where
|
||||
.map(|h| throw_error::set_error_hook(Arc::clone(h)));
|
||||
let value = self.invoke();
|
||||
if let Some(mut state) = prev {
|
||||
value.rebuild(&mut state, extra_attrs.clone());
|
||||
value.rebuild(&mut state);
|
||||
state
|
||||
} else {
|
||||
value.build(extra_attrs.clone())
|
||||
value.build()
|
||||
}
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
let new = self.build(extra_attrs);
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let new = self.build();
|
||||
let mut old = std::mem::replace(state, new);
|
||||
old.insert_before_this(state);
|
||||
old.unmount();
|
||||
@@ -123,6 +119,13 @@ where
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
self.0
|
||||
.as_ref()
|
||||
.map(|inner| inner.elements())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, V> RenderHtml for F
|
||||
@@ -132,22 +135,18 @@ where
|
||||
V::State: 'static,
|
||||
{
|
||||
type AsyncOutput = V::AsyncOutput;
|
||||
type Owned = F;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
self.invoke().dry_resolve(extra_attrs);
|
||||
fn dry_resolve(&mut self) {
|
||||
self.invoke().dry_resolve();
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
mut self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
self.invoke().resolve(extra_attrs).await
|
||||
async fn resolve(mut self) -> Self::AsyncOutput {
|
||||
self.invoke().resolve().await
|
||||
}
|
||||
|
||||
fn html_len(&self, _extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
V::MIN_LENGTH
|
||||
}
|
||||
|
||||
@@ -157,7 +156,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
let value = self.invoke();
|
||||
value.to_html_with_buf(
|
||||
@@ -175,7 +174,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -193,7 +192,6 @@ where
|
||||
mut self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let cursor = cursor.clone();
|
||||
let position = position.clone();
|
||||
@@ -204,22 +202,14 @@ where
|
||||
.map(|h| throw_error::set_error_hook(Arc::clone(h)));
|
||||
let value = self.invoke();
|
||||
if let Some(mut state) = prev {
|
||||
value.rebuild(&mut state, extra_attrs.clone());
|
||||
value.rebuild(&mut state);
|
||||
state
|
||||
} else {
|
||||
value.hydrate::<FROM_SERVER>(
|
||||
&cursor,
|
||||
&position,
|
||||
extra_attrs.clone(),
|
||||
)
|
||||
value.hydrate::<FROM_SERVER>(&cursor, &position)
|
||||
}
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, V> AddAnyAttr for F
|
||||
@@ -264,6 +254,11 @@ where
|
||||
self.with_value_mut(|value| value.insert_before_this(child))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
self.with_value_mut(|inner| inner.elements())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, E> Mountable for Result<M, E>
|
||||
@@ -293,6 +288,12 @@ where
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
self.as_ref()
|
||||
.map(|inner| inner.elements())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic attributes
|
||||
@@ -539,8 +540,8 @@ mod stable {
|
||||
hydration::Cursor,
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Mountable, Position,
|
||||
PositionState, Render, RenderHtml,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
},
|
||||
};
|
||||
#[allow(deprecated)]
|
||||
@@ -565,20 +566,13 @@ mod stable {
|
||||
type State = RenderEffectState<V::State>;
|
||||
|
||||
#[track_caller]
|
||||
fn build(
|
||||
self,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
(move || self.get()).build(extra_attrs)
|
||||
fn build(self) -> Self::State {
|
||||
(move || self.get()).build()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
let new = self.build(extra_attrs);
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let new = self.build();
|
||||
let mut old = std::mem::replace(state, new);
|
||||
old.insert_before_this(state);
|
||||
old.unmount();
|
||||
@@ -611,27 +605,20 @@ mod stable {
|
||||
V::State: 'static,
|
||||
{
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
if $dry_resolve {
|
||||
_ = self.get();
|
||||
}
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
fn html_len(
|
||||
&self,
|
||||
_extra_attrs: Option<Vec<&AnyAttribute>>,
|
||||
) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
V::MIN_LENGTH
|
||||
}
|
||||
|
||||
@@ -641,7 +628,7 @@ mod stable {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
let value = self.get();
|
||||
value.to_html_with_buf(
|
||||
@@ -659,7 +646,7 @@ mod stable {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -677,17 +664,9 @@ mod stable {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
(move || self.get()).hydrate::<FROM_SERVER>(
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs,
|
||||
)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
(move || self.get())
|
||||
.hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -764,20 +743,13 @@ mod stable {
|
||||
type State = RenderEffectState<V::State>;
|
||||
|
||||
#[track_caller]
|
||||
fn build(
|
||||
self,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
(move || self.get()).build(extra_attrs)
|
||||
fn build(self) -> Self::State {
|
||||
(move || self.get()).build()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
let new = self.build(extra_attrs);
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let new = self.build();
|
||||
let mut old = std::mem::replace(state, new);
|
||||
old.insert_before_this(state);
|
||||
old.unmount();
|
||||
@@ -816,27 +788,20 @@ mod stable {
|
||||
V::State: 'static,
|
||||
{
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
if $dry_resolve {
|
||||
_ = self.get();
|
||||
}
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
fn html_len(
|
||||
&self,
|
||||
_extra_attrs: Option<Vec<&AnyAttribute>>,
|
||||
) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
V::MIN_LENGTH
|
||||
}
|
||||
|
||||
@@ -846,7 +811,7 @@ mod stable {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
let value = self.get();
|
||||
value.to_html_with_buf(
|
||||
@@ -864,7 +829,7 @@ mod stable {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -882,17 +847,9 @@ mod stable {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
(move || self.get()).hydrate::<FROM_SERVER>(
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs,
|
||||
)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
(move || self.get())
|
||||
.hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,7 +942,7 @@ mod tests {
|
||||
let count = RwSignal::new(0);
|
||||
let app: HtmlElement<_, _, _, MockDom> =
|
||||
button((), move || count.get().to_string());
|
||||
let el = app.build(None);
|
||||
let el = app.build();
|
||||
assert_eq!(el.el.to_debug_html(), "<button>0</button>");
|
||||
rt.dispose();
|
||||
}
|
||||
@@ -996,7 +953,7 @@ mod tests {
|
||||
let count = RwSignal::new(0);
|
||||
let app: HtmlElement<_, _, _, MockDom> =
|
||||
button((), move || count.get().to_string());
|
||||
let el = app.build(None);
|
||||
let el = app.build();
|
||||
assert_eq!(el.el.to_debug_html(), "<button>0</button>");
|
||||
count.set(1);
|
||||
assert_eq!(el.el.to_debug_html(), "<button>1</button>");
|
||||
@@ -1014,7 +971,7 @@ mod tests {
|
||||
("Hello, my ", move || count.get().to_string(), " friends."),
|
||||
),
|
||||
);
|
||||
let el = app.build(None);
|
||||
let el = app.build();
|
||||
assert_eq!(
|
||||
el.el.to_debug_html(),
|
||||
"<main><button>Hello, my 0 friends.</button></main>"
|
||||
|
||||
@@ -3,10 +3,7 @@ use crate::{
|
||||
hydration::Cursor,
|
||||
prelude::Mountable,
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Position, PositionState,
|
||||
Render, RenderHtml,
|
||||
},
|
||||
view::{add_attr::AddAnyAttr, Position, PositionState, Render, RenderHtml},
|
||||
};
|
||||
use reactive_graph::{computed::ScopedFuture, owner::Owner};
|
||||
|
||||
@@ -56,18 +53,14 @@ where
|
||||
{
|
||||
type State = OwnedViewState<T::State>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
let state = self.owner.with(|| self.view.build(extra_attrs));
|
||||
fn build(self) -> Self::State {
|
||||
let state = self.owner.with(|| self.view.build());
|
||||
OwnedViewState::new(state, self.owner)
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let OwnedView { owner, view, .. } = self;
|
||||
owner.with(|| view.rebuild(&mut state.state, extra_attrs));
|
||||
owner.with(|| view.rebuild(&mut state.state));
|
||||
state.owner = owner;
|
||||
}
|
||||
}
|
||||
@@ -99,7 +92,6 @@ where
|
||||
{
|
||||
// TODO
|
||||
type AsyncOutput = OwnedView<T::AsyncOutput>;
|
||||
type Owned = OwnedView<T::Owned>;
|
||||
|
||||
const MIN_LENGTH: usize = T::MIN_LENGTH;
|
||||
|
||||
@@ -109,7 +101,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
self.owner.with(|| {
|
||||
self.view.to_html_with_buf(
|
||||
@@ -128,7 +120,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -153,39 +145,23 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let state = self.owner.with(|| {
|
||||
self.view
|
||||
.hydrate::<FROM_SERVER>(cursor, position, extra_attrs)
|
||||
});
|
||||
let state = self
|
||||
.owner
|
||||
.with(|| self.view.hydrate::<FROM_SERVER>(cursor, position));
|
||||
OwnedViewState::new(state, self.owner)
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
let OwnedView { owner, view } = self;
|
||||
let view = owner
|
||||
.with(|| {
|
||||
ScopedFuture::new(
|
||||
async move { view.resolve(extra_attrs).await },
|
||||
)
|
||||
})
|
||||
.with(|| ScopedFuture::new(async move { view.resolve().await }))
|
||||
.await;
|
||||
OwnedView { owner, view }
|
||||
}
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
self.owner.with(|| self.view.dry_resolve(extra_attrs));
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
OwnedView {
|
||||
owner: self.owner,
|
||||
view: self.view.into_owned(),
|
||||
}
|
||||
fn dry_resolve(&mut self) {
|
||||
self.owner.with(|| self.view.dry_resolve());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,4 +184,8 @@ where
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.state.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
self.state.elements()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ use crate::{
|
||||
hydration::Cursor,
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, iterators::OptionState,
|
||||
Mountable, Position, PositionState, Render, RenderHtml,
|
||||
add_attr::AddAnyAttr, iterators::OptionState, Mountable, Position,
|
||||
PositionState, Render, RenderHtml,
|
||||
},
|
||||
};
|
||||
use any_spawner::Executor;
|
||||
@@ -161,6 +161,10 @@ where
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.inner.borrow_mut().insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
self.inner.borrow().elements()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Render for Suspend<T>
|
||||
@@ -169,7 +173,7 @@ where
|
||||
{
|
||||
type State = SuspendState<T>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let Self { subscriber, inner } = self;
|
||||
|
||||
// create a Future that will be aborted on on_cleanup
|
||||
@@ -184,7 +188,7 @@ where
|
||||
// otherwise, start with the fallback
|
||||
let initial = fut.as_mut().now_or_never().and_then(Result::ok);
|
||||
let initially_pending = initial.is_none();
|
||||
let inner = Rc::new(RefCell::new(initial.build(extra_attrs.clone())));
|
||||
let inner = Rc::new(RefCell::new(initial.build()));
|
||||
|
||||
// get a unique ID if there's a SuspenseContext
|
||||
let id = use_context::<SuspenseContext>().map(|sc| sc.task_id());
|
||||
@@ -205,8 +209,7 @@ where
|
||||
drop(id);
|
||||
|
||||
if let Ok(value) = value {
|
||||
Some(value)
|
||||
.rebuild(&mut *state.borrow_mut(), extra_attrs);
|
||||
Some(value).rebuild(&mut *state.borrow_mut());
|
||||
}
|
||||
|
||||
subscriber.forward();
|
||||
@@ -219,11 +222,7 @@ where
|
||||
SuspendState { inner }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let Self { subscriber, inner } = self;
|
||||
|
||||
// create a Future that will be aborted on on_cleanup
|
||||
@@ -253,7 +252,7 @@ where
|
||||
// has no parent
|
||||
Executor::tick().await;
|
||||
if let Ok(value) = value {
|
||||
Some(value).rebuild(&mut *state.borrow_mut(), extra_attrs);
|
||||
Some(value).rebuild(&mut *state.borrow_mut());
|
||||
}
|
||||
|
||||
subscriber.forward();
|
||||
@@ -289,7 +288,6 @@ where
|
||||
T: RenderHtml + Sized + 'static,
|
||||
{
|
||||
type AsyncOutput = Option<T>;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = T::MIN_LENGTH;
|
||||
|
||||
@@ -299,7 +297,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
// TODO wrap this with a Suspense as needed
|
||||
// currently this is just used for Routes, which creates a Suspend but never actually needs
|
||||
@@ -321,7 +319,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -399,7 +397,6 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let Self { subscriber, inner } = self;
|
||||
|
||||
@@ -415,11 +412,9 @@ where
|
||||
// otherwise, start with the fallback
|
||||
let initial = fut.as_mut().now_or_never().and_then(Result::ok);
|
||||
let initially_pending = initial.is_none();
|
||||
let inner = Rc::new(RefCell::new(initial.hydrate::<FROM_SERVER>(
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs.clone(),
|
||||
)));
|
||||
let inner = Rc::new(RefCell::new(
|
||||
initial.hydrate::<FROM_SERVER>(cursor, position),
|
||||
));
|
||||
|
||||
// get a unique ID if there's a SuspenseContext
|
||||
let id = use_context::<SuspenseContext>().map(|sc| sc.task_id());
|
||||
@@ -440,8 +435,7 @@ where
|
||||
drop(id);
|
||||
|
||||
if let Ok(value) = value {
|
||||
Some(value)
|
||||
.rebuild(&mut *state.borrow_mut(), extra_attrs);
|
||||
Some(value).rebuild(&mut *state.borrow_mut());
|
||||
}
|
||||
|
||||
subscriber.forward();
|
||||
@@ -454,14 +448,11 @@ where
|
||||
SuspendState { inner }
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
Some(self.inner.await)
|
||||
}
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
// this is a little crazy, but if a Suspend is immediately available, we end up
|
||||
// with a situation where polling it multiple times (here in dry_resolve and then in
|
||||
// resolve) causes a runtime panic
|
||||
@@ -481,8 +472,4 @@ where
|
||||
as Pin<Box<dyn Future<Output = T> + Send>>;
|
||||
}
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,6 +466,10 @@ impl Mountable for Node {
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl Mountable for Text {
|
||||
@@ -486,6 +490,10 @@ impl Mountable for Text {
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl Mountable for Comment {
|
||||
@@ -506,6 +514,10 @@ impl Mountable for Comment {
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl Mountable for Element {
|
||||
@@ -526,6 +538,10 @@ impl Mountable for Element {
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![self.clone()]
|
||||
}
|
||||
}
|
||||
|
||||
impl CastFrom<Node> for Text {
|
||||
|
||||
@@ -106,7 +106,7 @@ impl StreamBuilder {
|
||||
fallback: View,
|
||||
position: &mut Position,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
View: RenderHtml,
|
||||
{
|
||||
@@ -165,7 +165,7 @@ impl StreamBuilder {
|
||||
view: impl Future<Output = Option<View>> + Send + 'static,
|
||||
position: &mut Position,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
View: RenderHtml,
|
||||
{
|
||||
@@ -185,7 +185,7 @@ impl StreamBuilder {
|
||||
position: &mut Position,
|
||||
mark_branches: bool,
|
||||
nonce: Option<Arc<str>>,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
View: RenderHtml,
|
||||
{
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#![allow(unused_mut)]
|
||||
#![allow(clippy::type_complexity)]
|
||||
#[cfg(feature = "ssr")]
|
||||
use super::MarkBranch;
|
||||
use super::{
|
||||
@@ -8,12 +6,13 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::{
|
||||
any_attribute::{AnyAttribute, IntoAnyAttribute},
|
||||
any_attribute::{AnyAttribute, AnyAttributeState, IntoAnyAttribute},
|
||||
Attribute,
|
||||
},
|
||||
hydration::Cursor,
|
||||
ssr::StreamBuilder,
|
||||
};
|
||||
use futures::future::{join, join_all};
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
fmt::Debug,
|
||||
@@ -34,15 +33,14 @@ use std::{future::Future, pin::Pin};
|
||||
pub struct AnyView {
|
||||
type_id: TypeId,
|
||||
value: Box<dyn Any + Send>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
build: fn(Box<dyn Any>, Option<Vec<AnyAttribute>>) -> AnyViewState,
|
||||
rebuild: fn(Box<dyn Any>, &mut AnyViewState, Option<Vec<AnyAttribute>>),
|
||||
build: fn(Box<dyn Any>) -> AnyViewState,
|
||||
rebuild: fn(TypeId, Box<dyn Any>, &mut AnyViewState),
|
||||
// The fields below are cfg-gated so they will not be included in WASM bundles if not needed.
|
||||
// Ordinarily, the compiler can simply omit this dead code because the methods are not called.
|
||||
// With this type-erased wrapper, however, the compiler is not *always* able to correctly
|
||||
// eliminate that code.
|
||||
#[cfg(feature = "ssr")]
|
||||
html_len: fn(&Box<dyn Any + Send>, Option<Vec<&AnyAttribute>>) -> usize,
|
||||
html_len: usize,
|
||||
#[cfg(feature = "ssr")]
|
||||
to_html: fn(
|
||||
Box<dyn Any>,
|
||||
@@ -50,7 +48,7 @@ pub struct AnyView {
|
||||
&mut Position,
|
||||
bool,
|
||||
bool,
|
||||
Option<Vec<AnyAttribute>>,
|
||||
Vec<AnyAttribute>,
|
||||
),
|
||||
#[cfg(feature = "ssr")]
|
||||
to_html_async: fn(
|
||||
@@ -59,7 +57,7 @@ pub struct AnyView {
|
||||
&mut Position,
|
||||
bool,
|
||||
bool,
|
||||
Option<Vec<AnyAttribute>>,
|
||||
Vec<AnyAttribute>,
|
||||
),
|
||||
#[cfg(feature = "ssr")]
|
||||
to_html_async_ooo: fn(
|
||||
@@ -68,26 +66,18 @@ pub struct AnyView {
|
||||
&mut Position,
|
||||
bool,
|
||||
bool,
|
||||
Option<Vec<AnyAttribute>>,
|
||||
Vec<AnyAttribute>,
|
||||
),
|
||||
#[cfg(feature = "ssr")]
|
||||
#[allow(clippy::type_complexity)]
|
||||
resolve: for<'a> fn(
|
||||
Box<dyn Any>,
|
||||
ExtraAttrsMut<'a>,
|
||||
)
|
||||
-> Pin<Box<dyn Future<Output = AnyView> + Send + 'a>>,
|
||||
resolve: fn(Box<dyn Any>) -> Pin<Box<dyn Future<Output = AnyView> + Send>>,
|
||||
#[cfg(feature = "ssr")]
|
||||
dry_resolve: fn(&mut Box<dyn Any + Send>, ExtraAttrsMut<'_>),
|
||||
dry_resolve: fn(&mut Box<dyn Any + Send>),
|
||||
#[cfg(feature = "hydrate")]
|
||||
#[cfg(feature = "hydrate")]
|
||||
#[allow(clippy::type_complexity)]
|
||||
hydrate_from_server: fn(
|
||||
Box<dyn Any>,
|
||||
&Cursor,
|
||||
&PositionState,
|
||||
Option<Vec<AnyAttribute>>,
|
||||
) -> AnyViewState,
|
||||
hydrate_from_server:
|
||||
fn(Box<dyn Any>, &Cursor, &PositionState) -> AnyViewState,
|
||||
}
|
||||
|
||||
/// Retained view state for [`AnyView`].
|
||||
@@ -101,6 +91,7 @@ pub struct AnyViewState {
|
||||
marker: Option<&crate::renderer::types::Node>,
|
||||
),
|
||||
insert_before_this: fn(&dyn Any, child: &mut dyn Mountable) -> bool,
|
||||
elements: fn(&dyn Any) -> Vec<crate::renderer::types::Element>,
|
||||
}
|
||||
|
||||
impl Debug for AnyViewState {
|
||||
@@ -157,51 +148,49 @@ where
|
||||
state.insert_before_this(child)
|
||||
}
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
fn resolve<'a, T>(
|
||||
value: Box<dyn Any>,
|
||||
extra_attrs: ExtraAttrsMut<'a>,
|
||||
) -> Pin<Box<dyn Future<Output = AnyView> + Send + 'a>>
|
||||
fn elements<T>(state: &dyn Any) -> Vec<crate::renderer::types::Element>
|
||||
where
|
||||
T: RenderHtml + 'static,
|
||||
T: Render,
|
||||
T::State: 'static,
|
||||
{
|
||||
let value = value
|
||||
.downcast::<T>()
|
||||
.expect("AnyView::resolve could not be downcast");
|
||||
Box::pin(async move { value.resolve(extra_attrs).await.into_any() })
|
||||
let state = state
|
||||
.downcast_ref::<T::State>()
|
||||
.expect("AnyViewState::insert_before_this couldn't downcast state");
|
||||
state.elements()
|
||||
}
|
||||
|
||||
impl<T> IntoAny for T
|
||||
where
|
||||
T: RenderHtml,
|
||||
T::Owned: Send,
|
||||
T: Send,
|
||||
T: RenderHtml + 'static,
|
||||
T::State: 'static,
|
||||
{
|
||||
fn into_any(self) -> AnyView {
|
||||
let value = Box::new(self.into_owned()) as Box<dyn Any + Send>;
|
||||
#[cfg(feature = "ssr")]
|
||||
let html_len = self.html_len();
|
||||
|
||||
let value = Box::new(self) as Box<dyn Any + Send>;
|
||||
|
||||
match value.downcast::<AnyView>() {
|
||||
// if it's already an AnyView, we don't need to double-wrap it
|
||||
Ok(any_view) => *any_view,
|
||||
Err(value) => {
|
||||
#[cfg(feature = "ssr")]
|
||||
let html_len =
|
||||
|value: &Box<dyn Any + Send>, extra_attrs: Option<Vec<&AnyAttribute>>| {
|
||||
let value = value
|
||||
.downcast_ref::<T::Owned>()
|
||||
.expect("AnyView::html_len could not be downcast");
|
||||
value.html_len(extra_attrs)
|
||||
};
|
||||
let dry_resolve = |value: &mut Box<dyn Any + Send>| {
|
||||
let value = value
|
||||
.downcast_mut::<T>()
|
||||
.expect("AnyView::resolve could not be downcast");
|
||||
value.dry_resolve();
|
||||
};
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
let dry_resolve =
|
||||
|value: &mut Box<dyn Any + Send>,
|
||||
extra_attrs: ExtraAttrsMut<'_>| {
|
||||
let value = value
|
||||
.downcast_mut::<T::Owned>()
|
||||
.expect("AnyView::resolve could not be downcast");
|
||||
value.dry_resolve(extra_attrs);
|
||||
};
|
||||
|
||||
let resolve = |value: Box<dyn Any>| {
|
||||
let value = value
|
||||
.downcast::<T>()
|
||||
.expect("AnyView::resolve could not be downcast");
|
||||
Box::pin(async move { value.resolve().await.into_any() })
|
||||
as Pin<Box<dyn Future<Output = AnyView> + Send>>
|
||||
};
|
||||
#[cfg(feature = "ssr")]
|
||||
let to_html =
|
||||
|value: Box<dyn Any>,
|
||||
@@ -209,12 +198,12 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>| {
|
||||
extra_attrs: Vec<AnyAttribute>| {
|
||||
let type_id = mark_branches
|
||||
.then(|| format!("{:?}", TypeId::of::<T::Owned>()))
|
||||
.then(|| format!("{:?}", TypeId::of::<T>()))
|
||||
.unwrap_or_default();
|
||||
let value = value
|
||||
.downcast::<T::Owned>()
|
||||
.downcast::<T>()
|
||||
.expect("AnyView::to_html could not be downcast");
|
||||
if mark_branches {
|
||||
buf.open_branch(&type_id);
|
||||
@@ -237,12 +226,12 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>| {
|
||||
extra_attrs: Vec<AnyAttribute>| {
|
||||
let type_id = mark_branches
|
||||
.then(|| format!("{:?}", TypeId::of::<T::Owned>()))
|
||||
.then(|| format!("{:?}", TypeId::of::<T>()))
|
||||
.unwrap_or_default();
|
||||
let value = value
|
||||
.downcast::<T::Owned>()
|
||||
.downcast::<T>()
|
||||
.expect("AnyView::to_html could not be downcast");
|
||||
if mark_branches {
|
||||
buf.open_branch(&type_id);
|
||||
@@ -259,91 +248,92 @@ where
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "ssr")]
|
||||
let to_html_async_ooo = |value: Box<dyn Any>,
|
||||
buf: &mut StreamBuilder,
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<
|
||||
Vec<AnyAttribute>,
|
||||
>| {
|
||||
let to_html_async_ooo =
|
||||
|value: Box<dyn Any>,
|
||||
buf: &mut StreamBuilder,
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Vec<AnyAttribute>| {
|
||||
let value = value
|
||||
.downcast::<T>()
|
||||
.expect("AnyView::to_html could not be downcast");
|
||||
value.to_html_async_with_buf::<true>(
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
extra_attrs,
|
||||
);
|
||||
};
|
||||
let build = |value: Box<dyn Any>| {
|
||||
let value = value
|
||||
.downcast::<T::Owned>()
|
||||
.expect("AnyView::to_html could not be downcast");
|
||||
value.to_html_async_with_buf::<true>(
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
extra_attrs,
|
||||
);
|
||||
};
|
||||
let build = |value: Box<dyn Any>, extra_attrs: Option<Vec<AnyAttribute>>| {
|
||||
let value = value
|
||||
.downcast::<T::Owned>()
|
||||
.downcast::<T>()
|
||||
.expect("AnyView::build couldn't downcast");
|
||||
let state = Box::new(value.build(extra_attrs));
|
||||
let state = Box::new(value.build());
|
||||
|
||||
AnyViewState {
|
||||
type_id: TypeId::of::<T::Owned>(),
|
||||
type_id: TypeId::of::<T>(),
|
||||
state,
|
||||
|
||||
mount: mount_any::<T::Owned>,
|
||||
unmount: unmount_any::<T::Owned>,
|
||||
insert_before_this: insert_before_this::<T::Owned>,
|
||||
mount: mount_any::<T>,
|
||||
unmount: unmount_any::<T>,
|
||||
insert_before_this: insert_before_this::<T>,
|
||||
elements: elements::<T>,
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "hydrate")]
|
||||
let hydrate_from_server = |value: Box<dyn Any>,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<
|
||||
Vec<AnyAttribute>,
|
||||
>| {
|
||||
let value = value.downcast::<T::Owned>().expect(
|
||||
"AnyView::hydrate_from_server couldn't downcast",
|
||||
);
|
||||
let state = Box::new(value.hydrate::<true>(
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs,
|
||||
));
|
||||
let hydrate_from_server =
|
||||
|value: Box<dyn Any>,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState| {
|
||||
let value = value.downcast::<T>().expect(
|
||||
"AnyView::hydrate_from_server couldn't downcast",
|
||||
);
|
||||
let state =
|
||||
Box::new(value.hydrate::<true>(cursor, position));
|
||||
|
||||
AnyViewState {
|
||||
type_id: TypeId::of::<T::Owned>(),
|
||||
state,
|
||||
|
||||
mount: mount_any::<T::Owned>,
|
||||
unmount: unmount_any::<T::Owned>,
|
||||
insert_before_this: insert_before_this::<T::Owned>,
|
||||
}
|
||||
};
|
||||
AnyViewState {
|
||||
type_id: TypeId::of::<T>(),
|
||||
state,
|
||||
mount: mount_any::<T>,
|
||||
unmount: unmount_any::<T>,
|
||||
insert_before_this: insert_before_this::<T>,
|
||||
elements: elements::<T>,
|
||||
}
|
||||
};
|
||||
|
||||
let rebuild =
|
||||
|value: Box<dyn Any>,
|
||||
state: &mut AnyViewState, extra_attrs: Option<Vec<AnyAttribute>>| {
|
||||
|new_type_id: TypeId,
|
||||
value: Box<dyn Any>,
|
||||
state: &mut AnyViewState| {
|
||||
let value = value
|
||||
.downcast::<T::Owned>()
|
||||
.downcast::<T>()
|
||||
.expect("AnyView::rebuild couldn't downcast value");
|
||||
let state = state.state.downcast_mut().expect(
|
||||
"AnyView::rebuild couldn't downcast state",
|
||||
);
|
||||
value.rebuild(state, extra_attrs);
|
||||
if new_type_id == state.type_id {
|
||||
let state = state.state.downcast_mut().expect(
|
||||
"AnyView::rebuild couldn't downcast state",
|
||||
);
|
||||
value.rebuild(state);
|
||||
} else {
|
||||
let mut new = value.into_any().build();
|
||||
state.insert_before_this(&mut new);
|
||||
state.unmount();
|
||||
*state = new;
|
||||
}
|
||||
};
|
||||
|
||||
AnyView {
|
||||
type_id: TypeId::of::<T::Owned>(),
|
||||
type_id: TypeId::of::<T>(),
|
||||
value,
|
||||
extra_attrs: vec![],
|
||||
build,
|
||||
rebuild,
|
||||
#[cfg(feature = "ssr")]
|
||||
html_len,
|
||||
#[cfg(feature = "ssr")]
|
||||
resolve: resolve::<T::Owned>,
|
||||
resolve,
|
||||
#[cfg(feature = "ssr")]
|
||||
dry_resolve,
|
||||
#[cfg(feature = "ssr")]
|
||||
html_len,
|
||||
#[cfg(feature = "ssr")]
|
||||
to_html,
|
||||
#[cfg(feature = "ssr")]
|
||||
to_html_async,
|
||||
@@ -357,206 +347,61 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Ignore, this is a hack for pre use<..> syntax.
|
||||
/// https://github.com/rust-lang/rfcs/blob/master/text/3498-lifetime-capture-rules-2024.md#the-captures-trick
|
||||
pub trait __Captures<T: ?Sized> {}
|
||||
impl<T: ?Sized, U: ?Sized> __Captures<T> for U {}
|
||||
|
||||
/// A mutable view into the extra attributes stored in an [`AnyView`].
|
||||
#[derive(Default)]
|
||||
pub struct ExtraAttrsMut<'a>(Option<Vec<&'a mut Vec<AnyAttribute>>>);
|
||||
impl<'a> ExtraAttrsMut<'a> {
|
||||
/// Create a new mutable view from owned attributes.
|
||||
pub fn from_owned(extra_attrs: &'a mut Option<Vec<AnyAttribute>>) -> Self {
|
||||
match extra_attrs {
|
||||
Some(extra_attrs) => {
|
||||
if extra_attrs.is_empty() {
|
||||
Self(None)
|
||||
} else {
|
||||
Self(Some(vec![extra_attrs]))
|
||||
}
|
||||
}
|
||||
None => Self(None),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
fn add_layer<'b>(
|
||||
mut self,
|
||||
extra_attrs: &'b mut Vec<AnyAttribute>,
|
||||
) -> ExtraAttrsMut<'b>
|
||||
where
|
||||
'a: 'b,
|
||||
{
|
||||
match (self.0, extra_attrs.is_empty()) {
|
||||
(Some(mut extra), false) => {
|
||||
extra.push(extra_attrs);
|
||||
ExtraAttrsMut(Some(extra))
|
||||
}
|
||||
(Some(mut extra), true) => {
|
||||
self.0 = Some(extra);
|
||||
self
|
||||
}
|
||||
(None, false) => ExtraAttrsMut(Some(vec![extra_attrs])),
|
||||
(None, true) => ExtraAttrsMut(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if there are any extra attributes.
|
||||
pub fn is_some(&self) -> bool {
|
||||
match &self.0 {
|
||||
Some(extra) => extra.is_empty(),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// "clone" the mutable view, to allow reuse in e.g. a for loop.
|
||||
/// The same as .as_deref_mut() on Option<&mut T>.
|
||||
pub fn as_deref_mut(&mut self) -> ExtraAttrsMut<'_> {
|
||||
ExtraAttrsMut(
|
||||
self.0
|
||||
.as_mut()
|
||||
.map(|inner| inner.iter_mut().map(|v| &mut **v).collect()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Iterate over the extra attributes.
|
||||
pub fn iter_mut(
|
||||
&mut self,
|
||||
) -> impl Iterator<Item = &mut AnyAttribute> + __Captures<&'a ()> + '_ {
|
||||
match &mut self.0 {
|
||||
Some(inner) => itertools::Either::Left(
|
||||
inner.iter_mut().flat_map(|v| v.iter_mut()),
|
||||
),
|
||||
None => itertools::Either::Right(std::iter::empty()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Call [`RenderHtml::resolve`] on any extra attributes in parallel.
|
||||
pub async fn resolve(self) {
|
||||
if let Some(extra_attr_groups) = self.0 {
|
||||
futures::future::join_all(extra_attr_groups.into_iter().map(
|
||||
|extra_attrs| async move {
|
||||
*extra_attrs =
|
||||
Attribute::resolve(std::mem::take(extra_attrs)).await;
|
||||
},
|
||||
))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn combine_owned_extra_attrs(
|
||||
parent_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) -> Option<Vec<AnyAttribute>> {
|
||||
let extra_attrs = if let Some(mut parent_extra_attrs) = parent_extra_attrs {
|
||||
for attr in extra_attrs {
|
||||
parent_extra_attrs.push(attr);
|
||||
}
|
||||
parent_extra_attrs
|
||||
} else {
|
||||
extra_attrs
|
||||
};
|
||||
if extra_attrs.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(extra_attrs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for AnyView {
|
||||
type State = AnyViewState;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
(self.build)(
|
||||
self.value,
|
||||
combine_owned_extra_attrs(extra_attrs, self.extra_attrs),
|
||||
)
|
||||
fn build(self) -> Self::State {
|
||||
(self.build)(self.value)
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
if self.type_id == state.type_id {
|
||||
(self.rebuild)(
|
||||
self.value,
|
||||
state,
|
||||
combine_owned_extra_attrs(extra_attrs, self.extra_attrs),
|
||||
)
|
||||
} else {
|
||||
let mut new = (self.build)(
|
||||
self.value,
|
||||
combine_owned_extra_attrs(extra_attrs, self.extra_attrs),
|
||||
);
|
||||
state.insert_before_this(&mut new);
|
||||
state.unmount();
|
||||
*state = new;
|
||||
}
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
(self.rebuild)(self.type_id, self.value, state)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAnyAttr for AnyView {
|
||||
type Output<SomeNewAttr: Attribute> = Self;
|
||||
type Output<SomeNewAttr: Attribute> = AnyViewWithAttrs;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn add_any_attr<NewAttr: Attribute>(
|
||||
mut self,
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml,
|
||||
{
|
||||
self.extra_attrs
|
||||
.push(attr.into_cloneable_owned().into_any_attr());
|
||||
self
|
||||
AnyViewWithAttrs {
|
||||
view: self,
|
||||
attrs: vec![attr.into_cloneable_owned().into_any_attr()],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderHtml for AnyView {
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
#[cfg(feature = "ssr")]
|
||||
{
|
||||
(self.dry_resolve)(
|
||||
&mut self.value,
|
||||
extra_attrs.add_layer(&mut self.extra_attrs),
|
||||
);
|
||||
(self.dry_resolve)(&mut self.value)
|
||||
}
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
_ = extra_attrs;
|
||||
panic!(
|
||||
"You are rendering AnyView to HTML without the `ssr` feature \
|
||||
enabled."
|
||||
);
|
||||
}
|
||||
panic!(
|
||||
"You are rendering AnyView to HTML without the `ssr` feature \
|
||||
enabled."
|
||||
);
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
mut self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
#[cfg(feature = "ssr")]
|
||||
{
|
||||
(self.resolve)(
|
||||
self.value,
|
||||
extra_attrs.add_layer(&mut self.extra_attrs),
|
||||
)
|
||||
.await
|
||||
(self.resolve)(self.value).await
|
||||
}
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
_ = extra_attrs;
|
||||
panic!(
|
||||
"You are rendering AnyView to HTML without the `ssr` feature \
|
||||
enabled."
|
||||
);
|
||||
}
|
||||
panic!(
|
||||
"You are rendering AnyView to HTML without the `ssr` feature \
|
||||
enabled."
|
||||
);
|
||||
}
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
@@ -567,19 +412,17 @@ impl RenderHtml for AnyView {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
#[cfg(feature = "ssr")]
|
||||
{
|
||||
(self.to_html)(
|
||||
self.value,
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
combine_owned_extra_attrs(extra_attrs, self.extra_attrs),
|
||||
);
|
||||
}
|
||||
(self.to_html)(
|
||||
self.value,
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
extra_attrs,
|
||||
);
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
_ = mark_branches;
|
||||
@@ -600,31 +443,29 @@ impl RenderHtml for AnyView {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
#[cfg(feature = "ssr")]
|
||||
{
|
||||
if OUT_OF_ORDER {
|
||||
(self.to_html_async_ooo)(
|
||||
self.value,
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
combine_owned_extra_attrs(extra_attrs, self.extra_attrs),
|
||||
);
|
||||
} else {
|
||||
(self.to_html_async)(
|
||||
self.value,
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
combine_owned_extra_attrs(extra_attrs, self.extra_attrs),
|
||||
);
|
||||
}
|
||||
if OUT_OF_ORDER {
|
||||
(self.to_html_async_ooo)(
|
||||
self.value,
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
extra_attrs,
|
||||
);
|
||||
} else {
|
||||
(self.to_html_async)(
|
||||
self.value,
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
extra_attrs,
|
||||
);
|
||||
}
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
@@ -644,29 +485,20 @@ impl RenderHtml for AnyView {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
#[cfg(feature = "hydrate")]
|
||||
{
|
||||
if FROM_SERVER {
|
||||
(self.hydrate_from_server)(
|
||||
self.value,
|
||||
cursor,
|
||||
position,
|
||||
combine_owned_extra_attrs(extra_attrs, self.extra_attrs),
|
||||
)
|
||||
} else {
|
||||
panic!(
|
||||
"hydrating AnyView from inside a ViewTemplate is not \
|
||||
supported."
|
||||
);
|
||||
}
|
||||
if FROM_SERVER {
|
||||
(self.hydrate_from_server)(self.value, cursor, position)
|
||||
} else {
|
||||
panic!(
|
||||
"hydrating AnyView from inside a ViewTemplate is not \
|
||||
supported."
|
||||
);
|
||||
}
|
||||
#[cfg(not(feature = "hydrate"))]
|
||||
{
|
||||
_ = cursor;
|
||||
_ = position;
|
||||
_ = extra_attrs;
|
||||
panic!(
|
||||
"You are trying to hydrate AnyView without the `hydrate` \
|
||||
feature enabled."
|
||||
@@ -674,34 +506,16 @@ impl RenderHtml for AnyView {
|
||||
}
|
||||
}
|
||||
|
||||
fn html_len(&self, extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
#[cfg(feature = "ssr")]
|
||||
{
|
||||
(self.html_len)(
|
||||
&self.value,
|
||||
match (extra_attrs, self.extra_attrs.is_empty()) {
|
||||
(Some(mut extra_attrs), false) => {
|
||||
for attr in &self.extra_attrs {
|
||||
extra_attrs.push(attr);
|
||||
}
|
||||
Some(extra_attrs)
|
||||
}
|
||||
(Some(extra_attrs), true) => Some(extra_attrs),
|
||||
(None, false) => Some(self.extra_attrs.iter().collect()),
|
||||
(None, true) => None,
|
||||
},
|
||||
)
|
||||
self.html_len
|
||||
}
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
{
|
||||
_ = extra_attrs;
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Mountable for AnyViewState {
|
||||
@@ -720,7 +534,163 @@ impl Mountable for AnyViewState {
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
(self.insert_before_this)(&*self.state, child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
(self.elements)(&*self.state)
|
||||
}
|
||||
}
|
||||
|
||||
/// wip
|
||||
pub struct AnyViewWithAttrs {
|
||||
view: AnyView,
|
||||
attrs: Vec<AnyAttribute>,
|
||||
}
|
||||
|
||||
impl Render for AnyViewWithAttrs {
|
||||
type State = AnyViewWithAttrsState;
|
||||
|
||||
fn build(self) -> Self::State {
|
||||
let view = self.view.build();
|
||||
let elements = view.elements();
|
||||
let mut attrs = Vec::with_capacity(elements.len() * self.attrs.len());
|
||||
for attr in self.attrs {
|
||||
for el in &elements {
|
||||
attrs.push(attr.clone().build(el))
|
||||
}
|
||||
}
|
||||
AnyViewWithAttrsState { view, attrs }
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
self.view.rebuild(&mut state.view);
|
||||
self.attrs.rebuild(&mut state.attrs);
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderHtml for AnyViewWithAttrs {
|
||||
type AsyncOutput = Self;
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self) {
|
||||
self.view.dry_resolve();
|
||||
for attr in &mut self.attrs {
|
||||
attr.dry_resolve();
|
||||
}
|
||||
}
|
||||
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
let resolve_view = self.view.resolve();
|
||||
let resolve_attrs =
|
||||
join_all(self.attrs.into_iter().map(|attr| attr.resolve()));
|
||||
let (view, attrs) = join(resolve_view, resolve_attrs).await;
|
||||
Self { view, attrs }
|
||||
}
|
||||
|
||||
fn to_html_with_buf(
|
||||
self,
|
||||
buf: &mut String,
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
mut extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
// `extra_attrs` will be empty here in most cases, but it will have
|
||||
// attributes in it already if this is, itself, receiving additional attrs
|
||||
extra_attrs.extend(self.attrs);
|
||||
self.view.to_html_with_buf(
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
extra_attrs,
|
||||
);
|
||||
}
|
||||
|
||||
fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
|
||||
self,
|
||||
buf: &mut StreamBuilder,
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
mut extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
extra_attrs.extend(self.attrs);
|
||||
self.view.to_html_async_with_buf::<OUT_OF_ORDER>(
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
extra_attrs,
|
||||
);
|
||||
}
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
) -> Self::State {
|
||||
let view = self.view.hydrate::<FROM_SERVER>(cursor, position);
|
||||
let elements = view.elements();
|
||||
let mut attrs = Vec::with_capacity(elements.len() * self.attrs.len());
|
||||
for attr in self.attrs {
|
||||
for el in &elements {
|
||||
attrs.push(attr.clone().hydrate::<FROM_SERVER>(el));
|
||||
}
|
||||
}
|
||||
AnyViewWithAttrsState { view, attrs }
|
||||
}
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.view.html_len()
|
||||
+ self.attrs.iter().map(|attr| attr.html_len()).sum::<usize>()
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAnyAttr for AnyViewWithAttrs {
|
||||
type Output<SomeNewAttr: Attribute> = AnyViewWithAttrs;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute>(
|
||||
mut self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml,
|
||||
{
|
||||
self.attrs.push(attr.into_cloneable_owned().into_any_attr());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// wip
|
||||
pub struct AnyViewWithAttrsState {
|
||||
view: AnyViewState,
|
||||
attrs: Vec<AnyAttributeState>,
|
||||
}
|
||||
|
||||
impl Mountable for AnyViewWithAttrsState {
|
||||
fn unmount(&mut self) {
|
||||
self.view.unmount();
|
||||
}
|
||||
|
||||
fn mount(
|
||||
&mut self,
|
||||
parent: &crate::renderer::types::Element,
|
||||
marker: Option<&crate::renderer::types::Node>,
|
||||
) {
|
||||
self.view.mount(parent, marker)
|
||||
}
|
||||
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.view.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
self.view.elements()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, MarkBranch, Mountable,
|
||||
Position, PositionState, Render, RenderHtml,
|
||||
add_attr::AddAnyAttr, MarkBranch, Mountable, Position, PositionState,
|
||||
Render, RenderHtml,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::{any_attribute::AnyAttribute, Attribute},
|
||||
@@ -17,33 +17,29 @@ where
|
||||
{
|
||||
type State = Either<A::State, B::State>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
match self {
|
||||
Either::Left(left) => Either::Left(left.build(extra_attrs)),
|
||||
Either::Right(right) => Either::Right(right.build(extra_attrs)),
|
||||
Either::Left(left) => Either::Left(left.build()),
|
||||
Either::Right(right) => Either::Right(right.build()),
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
match (self, &mut *state) {
|
||||
(Either::Left(new), Either::Left(old)) => {
|
||||
new.rebuild(old, extra_attrs);
|
||||
new.rebuild(old);
|
||||
}
|
||||
(Either::Right(new), Either::Right(old)) => {
|
||||
new.rebuild(old, extra_attrs);
|
||||
new.rebuild(old);
|
||||
}
|
||||
(Either::Right(new), Either::Left(old)) => {
|
||||
let mut new_state = new.build(extra_attrs);
|
||||
let mut new_state = new.build();
|
||||
old.insert_before_this(&mut new_state);
|
||||
old.unmount();
|
||||
*state = Either::Right(new_state);
|
||||
}
|
||||
(Either::Left(new), Either::Right(old)) => {
|
||||
let mut new_state = new.build(extra_attrs);
|
||||
let mut new_state = new.build();
|
||||
old.insert_before_this(&mut new_state);
|
||||
old.unmount();
|
||||
*state = Either::Left(new_state);
|
||||
@@ -81,6 +77,13 @@ where
|
||||
Either::Right(right) => right.insert_before_this(child),
|
||||
}
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
match &self {
|
||||
Either::Left(left) => left.elements(),
|
||||
Either::Right(right) => right.elements(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> AddAnyAttr for Either<A, B>
|
||||
@@ -126,34 +129,28 @@ where
|
||||
B: RenderHtml,
|
||||
{
|
||||
type AsyncOutput = Either<A::AsyncOutput, B::AsyncOutput>;
|
||||
type Owned = Either<A::Owned, B::Owned>;
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
match self {
|
||||
Either::Left(left) => left.dry_resolve(extra_attrs),
|
||||
Either::Right(right) => right.dry_resolve(extra_attrs),
|
||||
Either::Left(left) => left.dry_resolve(),
|
||||
Either::Right(right) => right.dry_resolve(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
match self {
|
||||
Either::Left(left) => Either::Left(left.resolve(extra_attrs).await),
|
||||
Either::Right(right) => {
|
||||
Either::Right(right.resolve(extra_attrs).await)
|
||||
}
|
||||
Either::Left(left) => Either::Left(left.resolve().await),
|
||||
Either::Right(right) => Either::Right(right.resolve().await),
|
||||
}
|
||||
}
|
||||
|
||||
const MIN_LENGTH: usize = max_usize(&[A::MIN_LENGTH, B::MIN_LENGTH]);
|
||||
|
||||
#[inline(always)]
|
||||
fn html_len(&self, extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
match self {
|
||||
Either::Left(i) => i.html_len(extra_attrs),
|
||||
Either::Right(i) => i.html_len(extra_attrs),
|
||||
Either::Left(i) => i.html_len(),
|
||||
Either::Right(i) => i.html_len(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +160,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
match self {
|
||||
Either::Left(left) => {
|
||||
@@ -205,7 +202,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -247,24 +244,14 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
match self {
|
||||
Either::Left(left) => Either::Left(left.hydrate::<FROM_SERVER>(
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs,
|
||||
)),
|
||||
Either::Right(right) => Either::Right(
|
||||
right.hydrate::<FROM_SERVER>(cursor, position, extra_attrs),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
match self {
|
||||
Either::Left(left) => Either::Left(left.into_owned()),
|
||||
Either::Right(right) => Either::Right(right.into_owned()),
|
||||
Either::Left(left) => {
|
||||
Either::Left(left.hydrate::<FROM_SERVER>(cursor, position))
|
||||
}
|
||||
Either::Right(right) => {
|
||||
Either::Right(right.hydrate::<FROM_SERVER>(cursor, position))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,29 +280,25 @@ where
|
||||
{
|
||||
type State = EitherKeepAliveState<A::State, B::State>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let showing_b = self.show_b;
|
||||
let a = self.a.map(|val| Render::build(val, extra_attrs.clone()));
|
||||
let b = self.b.map(|val| Render::build(val, extra_attrs));
|
||||
let a = self.a.map(Render::build);
|
||||
let b = self.b.map(Render::build);
|
||||
EitherKeepAliveState { a, b, showing_b }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
// set or update A -- `None` just means "no change"
|
||||
match (self.a, &mut state.a) {
|
||||
(Some(new), Some(old)) => new.rebuild(old, extra_attrs.clone()),
|
||||
(Some(new), None) => state.a = Some(new.build(extra_attrs.clone())),
|
||||
(Some(new), Some(old)) => new.rebuild(old),
|
||||
(Some(new), None) => state.a = Some(new.build()),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// set or update B
|
||||
match (self.b, &mut state.b) {
|
||||
(Some(new), Some(old)) => new.rebuild(old, extra_attrs),
|
||||
(Some(new), None) => state.b = Some(new.build(extra_attrs)),
|
||||
(Some(new), Some(old)) => new.rebuild(old),
|
||||
(Some(new), None) => state.b = Some(new.build()),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -375,58 +358,35 @@ where
|
||||
B: RenderHtml,
|
||||
{
|
||||
type AsyncOutput = EitherKeepAlive<A::AsyncOutput, B::AsyncOutput>;
|
||||
type Owned = EitherKeepAlive<A::Owned, B::Owned>;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, mut extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
if let Some(inner) = &mut self.a {
|
||||
inner.dry_resolve(extra_attrs.as_deref_mut());
|
||||
inner.dry_resolve();
|
||||
}
|
||||
if let Some(inner) = &mut self.b {
|
||||
inner.dry_resolve(extra_attrs);
|
||||
inner.dry_resolve();
|
||||
}
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
mut extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
let EitherKeepAlive { a, b, show_b } = self;
|
||||
|
||||
// Has to be sequential if extra attrs are present:
|
||||
let (a, b) = if extra_attrs.is_some() {
|
||||
let a = match a {
|
||||
Some(a) => Some(a.resolve(extra_attrs.as_deref_mut()).await),
|
||||
None => None,
|
||||
};
|
||||
let b = match b {
|
||||
Some(b) => Some(b.resolve(extra_attrs.as_deref_mut()).await),
|
||||
None => None,
|
||||
};
|
||||
(a, b)
|
||||
} else {
|
||||
join(
|
||||
async move {
|
||||
match a {
|
||||
Some(a) => {
|
||||
Some(a.resolve(ExtraAttrsMut::default()).await)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
},
|
||||
async move {
|
||||
match b {
|
||||
Some(b) => {
|
||||
Some(b.resolve(ExtraAttrsMut::default()).await)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
},
|
||||
)
|
||||
.await
|
||||
};
|
||||
|
||||
let (a, b) = join(
|
||||
async move {
|
||||
match a {
|
||||
Some(a) => Some(a.resolve().await),
|
||||
None => None,
|
||||
}
|
||||
},
|
||||
async move {
|
||||
match b {
|
||||
Some(b) => Some(b.resolve().await),
|
||||
None => None,
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
EitherKeepAlive { a, b, show_b }
|
||||
}
|
||||
|
||||
@@ -436,7 +396,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
if self.show_b {
|
||||
self.b
|
||||
@@ -467,7 +427,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -498,34 +458,25 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let showing_b = self.show_b;
|
||||
let a = self.a.map(|a| {
|
||||
if showing_b {
|
||||
a.build(extra_attrs.clone())
|
||||
a.build()
|
||||
} else {
|
||||
a.hydrate::<FROM_SERVER>(cursor, position, extra_attrs.clone())
|
||||
a.hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
});
|
||||
let b = self.b.map(|b| {
|
||||
if showing_b {
|
||||
b.hydrate::<FROM_SERVER>(cursor, position, extra_attrs)
|
||||
b.hydrate::<FROM_SERVER>(cursor, position)
|
||||
} else {
|
||||
b.build(extra_attrs)
|
||||
b.build()
|
||||
}
|
||||
});
|
||||
|
||||
EitherKeepAliveState { showing_b, a, b }
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
EitherKeepAlive {
|
||||
a: self.a.map(|a| a.into_owned()),
|
||||
b: self.b.map(|b| b.into_owned()),
|
||||
show_b: self.show_b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> Mountable for EitherKeepAliveState<A, B>
|
||||
@@ -572,6 +523,20 @@ where
|
||||
.insert_before_this(child)
|
||||
}
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
if self.showing_b {
|
||||
self.b
|
||||
.as_ref()
|
||||
.map(|inner| inner.elements())
|
||||
.unwrap_or_default()
|
||||
} else {
|
||||
self.a
|
||||
.as_ref()
|
||||
.map(|inner| inner.elements())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! tuples {
|
||||
@@ -615,6 +580,12 @@ macro_rules! tuples {
|
||||
$([<EitherOf $num>]::$ty(this) =>this.insert_before_this(child),)*
|
||||
}
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
match &self.state {
|
||||
$([<EitherOf $num>]::$ty(this) => this.elements(),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($ty,)*> Render for [<EitherOf $num>]<$($ty,)*>
|
||||
@@ -625,20 +596,20 @@ macro_rules! tuples {
|
||||
type State = [<EitherOf $num State>]<$($ty,)*>;
|
||||
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let state = match self {
|
||||
$([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.build(extra_attrs)),)*
|
||||
$([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.build()),)*
|
||||
};
|
||||
Self::State { state }
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, extra_attrs: Option<Vec<AnyAttribute>>) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let new_state = match (self, &mut state.state) {
|
||||
// rebuild same state and return early
|
||||
$(([<EitherOf $num>]::$ty(new), [<EitherOf $num>]::$ty(old)) => { return new.rebuild(old, extra_attrs); },)*
|
||||
$(([<EitherOf $num>]::$ty(new), [<EitherOf $num>]::$ty(old)) => { return new.rebuild(old); },)*
|
||||
// or mount new state
|
||||
$(([<EitherOf $num>]::$ty(new), _) => {
|
||||
let mut new = new.build(extra_attrs);
|
||||
let mut new = new.build();
|
||||
state.insert_before_this(&mut new);
|
||||
[<EitherOf $num>]::$ty(new)
|
||||
},)*
|
||||
@@ -682,33 +653,39 @@ macro_rules! tuples {
|
||||
|
||||
{
|
||||
type AsyncOutput = [<EitherOf $num>]<$($ty::AsyncOutput,)*>;
|
||||
type Owned = [<EitherOf $num>]<$($ty::Owned,)*>;
|
||||
|
||||
const MIN_LENGTH: usize = max_usize(&[$($ty ::MIN_LENGTH,)*]);
|
||||
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
match self {
|
||||
$([<EitherOf $num>]::$ty(this) => {
|
||||
this.dry_resolve(extra_attrs);
|
||||
this.dry_resolve();
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
||||
async fn resolve(self, extra_attrs: ExtraAttrsMut<'_>) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
match self {
|
||||
$([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.resolve(extra_attrs).await),)*
|
||||
$([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.resolve().await),)*
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn html_len(&self, extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
match self {
|
||||
$([<EitherOf $num>]::$ty(i) => i.html_len(extra_attrs),)*
|
||||
$([<EitherOf $num>]::$ty(i) => i.html_len(),)*
|
||||
}
|
||||
}
|
||||
|
||||
fn to_html_with_buf(self, buf: &mut String, position: &mut Position, escape: bool, mark_branches: bool, extra_attrs: Option<Vec<AnyAttribute>>) {
|
||||
fn to_html_with_buf(
|
||||
self,
|
||||
buf: &mut String,
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Vec<AnyAttribute>
|
||||
) {
|
||||
match self {
|
||||
$([<EitherOf $num>]::$ty(this) => {
|
||||
if mark_branches {
|
||||
@@ -724,7 +701,12 @@ macro_rules! tuples {
|
||||
|
||||
fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
|
||||
self,
|
||||
buf: &mut StreamBuilder, position: &mut Position, escape: bool, mark_branches: bool, extra_attrs: Option<Vec<AnyAttribute>>) where
|
||||
buf: &mut StreamBuilder,
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Vec<AnyAttribute>
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
match self {
|
||||
@@ -744,24 +726,15 @@ macro_rules! tuples {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let state = match self {
|
||||
$([<EitherOf $num>]::$ty(this) => {
|
||||
[<EitherOf $num>]::$ty(this.hydrate::<FROM_SERVER>(cursor, position, extra_attrs))
|
||||
[<EitherOf $num>]::$ty(this.hydrate::<FROM_SERVER>(cursor, position))
|
||||
})*
|
||||
};
|
||||
|
||||
Self::State { state }
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
match self {
|
||||
$([<EitherOf $num>]::$ty(this) => {
|
||||
[<EitherOf $num>]::$ty(this.into_owned())
|
||||
})*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use super::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Position, PositionState,
|
||||
RenderHtml,
|
||||
};
|
||||
use super::{add_attr::AddAnyAttr, Position, PositionState, RenderHtml};
|
||||
use crate::{
|
||||
html::attribute::{any_attribute::AnyAttribute, Attribute},
|
||||
hydration::Cursor,
|
||||
@@ -19,23 +16,19 @@ where
|
||||
{
|
||||
type State = ResultState<T>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let hook = throw_error::get_error_hook();
|
||||
let (state, error) = match self {
|
||||
Ok(view) => (Either::Left(view.build(extra_attrs)), None),
|
||||
Ok(view) => (Either::Left(view.build()), None),
|
||||
Err(e) => (
|
||||
Either::Right(Render::build((), None)),
|
||||
Either::Right(Render::build(())),
|
||||
Some(throw_error::throw(e.into())),
|
||||
),
|
||||
};
|
||||
ResultState { state, error, hook }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let _guard = state.hook.clone().map(throw_error::set_error_hook);
|
||||
match (&mut state.state, self) {
|
||||
// both errors: throw the new error and replace
|
||||
@@ -44,11 +37,11 @@ where
|
||||
}
|
||||
// both Ok: need to rebuild child
|
||||
(Either::Left(old), Ok(new)) => {
|
||||
T::rebuild(new, old, extra_attrs);
|
||||
T::rebuild(new, old);
|
||||
}
|
||||
// Ok => Err: unmount, replace with marker, and throw
|
||||
(Either::Left(old), Err(err)) => {
|
||||
let mut new_state = Render::build((), None);
|
||||
let mut new_state = Render::build(());
|
||||
old.insert_before_this(&mut new_state);
|
||||
old.unmount();
|
||||
state.state = Either::Right(new_state);
|
||||
@@ -59,7 +52,7 @@ where
|
||||
if let Some(err) = state.error.take() {
|
||||
throw_error::clear(&err);
|
||||
}
|
||||
let mut new_state = new.build(extra_attrs);
|
||||
let mut new_state = new.build();
|
||||
old.insert_before_this(&mut new_state);
|
||||
old.unmount();
|
||||
state.state = Either::Left(new_state);
|
||||
@@ -111,6 +104,10 @@ where
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.state.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
self.state.elements()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> AddAnyAttr for Result<T, E>
|
||||
@@ -139,29 +136,25 @@ where
|
||||
E: Into<AnyError> + Send + 'static,
|
||||
{
|
||||
type AsyncOutput = Result<T::AsyncOutput, E>;
|
||||
type Owned = Result<T::Owned, E>;
|
||||
|
||||
const MIN_LENGTH: usize = T::MIN_LENGTH;
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
if let Ok(inner) = self.as_mut() {
|
||||
inner.dry_resolve(extra_attrs)
|
||||
inner.dry_resolve()
|
||||
}
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
match self {
|
||||
Ok(view) => Ok(view.resolve(extra_attrs).await),
|
||||
Ok(view) => Ok(view.resolve().await),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
fn html_len(&self, extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
match self {
|
||||
Ok(i) => i.html_len(extra_attrs) + 3,
|
||||
Ok(i) => i.html_len() + 3,
|
||||
Err(_) => 0,
|
||||
}
|
||||
}
|
||||
@@ -172,16 +165,18 @@ where
|
||||
position: &mut super::Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
match self {
|
||||
Ok(inner) => inner.to_html_with_buf(
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
extra_attrs,
|
||||
),
|
||||
Ok(inner) => {
|
||||
inner.to_html_with_buf(
|
||||
buf,
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
extra_attrs,
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
buf.push_str("<!>");
|
||||
throw_error::throw(e);
|
||||
@@ -195,7 +190,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -218,35 +213,19 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let hook = throw_error::get_error_hook();
|
||||
let (state, error) = match self {
|
||||
Ok(view) => (
|
||||
Either::Left(view.hydrate::<FROM_SERVER>(
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs,
|
||||
)),
|
||||
Either::Left(view.hydrate::<FROM_SERVER>(cursor, position)),
|
||||
None,
|
||||
),
|
||||
Err(e) => {
|
||||
let state = RenderHtml::hydrate::<FROM_SERVER>(
|
||||
(),
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs,
|
||||
);
|
||||
let state =
|
||||
RenderHtml::hydrate::<FROM_SERVER>((), cursor, position);
|
||||
(Either::Right(state), Some(throw_error::throw(e.into())))
|
||||
}
|
||||
};
|
||||
ResultState { state, error, hook }
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
match self {
|
||||
Ok(view) => Ok(view.into_owned()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut,
|
||||
batch_resolve_items_with_extra_attrs, Mountable, Position, PositionState,
|
||||
Render, RenderHtml,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::{any_attribute::AnyAttribute, Attribute},
|
||||
@@ -21,24 +20,20 @@ where
|
||||
{
|
||||
type State = OptionState<T>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
match self {
|
||||
Some(value) => Either::Left(value),
|
||||
None => Either::Right(()),
|
||||
}
|
||||
.build(extra_attrs)
|
||||
.build()
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
match self {
|
||||
Some(value) => Either::Left(value),
|
||||
None => Either::Right(()),
|
||||
}
|
||||
.rebuild(state, extra_attrs)
|
||||
.rebuild(state)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,29 +60,25 @@ where
|
||||
T: RenderHtml,
|
||||
{
|
||||
type AsyncOutput = Option<T::AsyncOutput>;
|
||||
type Owned = Option<T::Owned>;
|
||||
|
||||
const MIN_LENGTH: usize = T::MIN_LENGTH;
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
if let Some(inner) = self.as_mut() {
|
||||
inner.dry_resolve(extra_attrs);
|
||||
inner.dry_resolve();
|
||||
}
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
match self {
|
||||
None => None,
|
||||
Some(value) => Some(value.resolve(extra_attrs).await),
|
||||
Some(value) => Some(value.resolve().await),
|
||||
}
|
||||
}
|
||||
|
||||
fn html_len(&self, extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
match self {
|
||||
Some(i) => i.html_len(extra_attrs) + 3,
|
||||
Some(i) => i.html_len() + 3,
|
||||
None => 3,
|
||||
}
|
||||
}
|
||||
@@ -98,7 +89,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
match self {
|
||||
Some(value) => Either::Left(value),
|
||||
@@ -119,7 +110,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -141,17 +132,12 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
match self {
|
||||
Some(value) => Either::Left(value),
|
||||
None => Either::Right(()),
|
||||
}
|
||||
.hydrate::<FROM_SERVER>(cursor, position, extra_attrs)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self.map(RenderHtml::into_owned)
|
||||
.hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,27 +147,20 @@ where
|
||||
{
|
||||
type State = VecState<T::State>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let marker = Rndr::create_placeholder();
|
||||
VecState {
|
||||
states: self
|
||||
.into_iter()
|
||||
.map(|val| T::build(val, extra_attrs.clone()))
|
||||
.collect(),
|
||||
states: self.into_iter().map(T::build).collect(),
|
||||
marker,
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let VecState { states, marker } = state;
|
||||
let old = states;
|
||||
// this is an unkeyed diff
|
||||
if old.is_empty() {
|
||||
let mut new = self.build(extra_attrs).states;
|
||||
let mut new = self.build().states;
|
||||
for item in new.iter_mut() {
|
||||
Rndr::mount_before(item, marker.as_ref());
|
||||
}
|
||||
@@ -198,10 +177,10 @@ where
|
||||
for item in self.into_iter().zip_longest(old.iter_mut()) {
|
||||
match item {
|
||||
itertools::EitherOrBoth::Both(new, old) => {
|
||||
T::rebuild(new, old, extra_attrs.clone())
|
||||
T::rebuild(new, old)
|
||||
}
|
||||
itertools::EitherOrBoth::Left(new) => {
|
||||
let mut new_state = new.build(extra_attrs.clone());
|
||||
let mut new_state = new.build();
|
||||
Rndr::mount_before(&mut new_state, marker.as_ref());
|
||||
adds.push(new_state);
|
||||
}
|
||||
@@ -259,6 +238,13 @@ where
|
||||
self.marker.insert_before_this(child)
|
||||
}
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
self.states
|
||||
.iter()
|
||||
.flat_map(|item| item.elements())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddAnyAttr for Vec<T>
|
||||
@@ -287,31 +273,24 @@ where
|
||||
T: RenderHtml,
|
||||
{
|
||||
type AsyncOutput = Vec<T::AsyncOutput>;
|
||||
type Owned = Vec<T::Owned>;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, mut extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
for inner in self.iter_mut() {
|
||||
inner.dry_resolve(extra_attrs.as_deref_mut());
|
||||
inner.dry_resolve();
|
||||
}
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
batch_resolve_items_with_extra_attrs(self, extra_attrs)
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
futures::future::join_all(self.into_iter().map(T::resolve))
|
||||
.await
|
||||
.into_iter()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn html_len(&self, extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
self.iter()
|
||||
.map(|n| n.html_len(extra_attrs.clone()))
|
||||
.sum::<usize>()
|
||||
+ 3
|
||||
fn html_len(&self) -> usize {
|
||||
self.iter().map(|n| n.html_len()).sum::<usize>() + 3
|
||||
}
|
||||
|
||||
fn to_html_with_buf(
|
||||
@@ -320,7 +299,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
let mut children = self.into_iter();
|
||||
if let Some(first) = children.next() {
|
||||
@@ -338,6 +317,7 @@ where
|
||||
position,
|
||||
escape,
|
||||
mark_branches,
|
||||
// each child will have the extra attributes applied
|
||||
extra_attrs.clone(),
|
||||
);
|
||||
}
|
||||
@@ -350,7 +330,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -380,27 +360,16 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let states = self
|
||||
.into_iter()
|
||||
.map(|child| {
|
||||
child.hydrate::<FROM_SERVER>(
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs.clone(),
|
||||
)
|
||||
})
|
||||
.map(|child| child.hydrate::<FROM_SERVER>(cursor, position))
|
||||
.collect();
|
||||
|
||||
let marker = cursor.next_placeholder(position);
|
||||
|
||||
VecState { states, marker }
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self.into_iter().map(RenderHtml::into_owned).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const N: usize> Render for [T; N]
|
||||
@@ -409,23 +378,19 @@ where
|
||||
{
|
||||
type State = ArrayState<T::State, N>;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
Self::State {
|
||||
states: self.map(|val| T::build(val, extra_attrs.clone())),
|
||||
states: self.map(T::build),
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let Self::State { states } = state;
|
||||
let old = states;
|
||||
// this is an unkeyed diff
|
||||
self.into_iter()
|
||||
.zip(old.iter_mut())
|
||||
.for_each(|(new, old)| T::rebuild(new, old, extra_attrs.clone()));
|
||||
.for_each(|(new, old)| T::rebuild(new, old));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,6 +427,13 @@ where
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
self.states
|
||||
.iter()
|
||||
.flat_map(|item| item.elements())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
impl<T, const N: usize> AddAnyAttr for [T; N]
|
||||
where
|
||||
@@ -487,21 +459,17 @@ where
|
||||
T: RenderHtml,
|
||||
{
|
||||
type AsyncOutput = [T::AsyncOutput; N];
|
||||
type Owned = Vec<T::Owned>;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, mut extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
for inner in self.iter_mut() {
|
||||
inner.dry_resolve(extra_attrs.as_deref_mut());
|
||||
inner.dry_resolve();
|
||||
}
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
batch_resolve_items_with_extra_attrs(self, extra_attrs)
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
futures::future::join_all(self.into_iter().map(T::resolve))
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>()
|
||||
@@ -509,10 +477,8 @@ where
|
||||
.unwrap_or_else(|_| unreachable!())
|
||||
}
|
||||
|
||||
fn html_len(&self, extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
self.iter()
|
||||
.map(|val| RenderHtml::html_len(val, extra_attrs.clone()))
|
||||
.sum::<usize>()
|
||||
fn html_len(&self) -> usize {
|
||||
self.iter().map(RenderHtml::html_len).sum::<usize>()
|
||||
}
|
||||
|
||||
fn to_html_with_buf(
|
||||
@@ -521,7 +487,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
for child in self.into_iter() {
|
||||
child.to_html_with_buf(
|
||||
@@ -540,7 +506,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -559,17 +525,9 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let states = self.map(|child| {
|
||||
child.hydrate::<FROM_SERVER>(cursor, position, extra_attrs.clone())
|
||||
});
|
||||
let states =
|
||||
self.map(|child| child.hydrate::<FROM_SERVER>(cursor, position));
|
||||
ArrayState { states }
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self.into_iter()
|
||||
.map(RenderHtml::into_owned)
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut,
|
||||
batch_resolve_items_with_extra_attrs, Mountable, Position, PositionState,
|
||||
Render, RenderHtml,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::{any_attribute::AnyAttribute, Attribute},
|
||||
@@ -76,7 +75,7 @@ where
|
||||
type State = KeyedState<K, VFS, V>;
|
||||
// TODO fallible state and try_build()/try_rebuild() here
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let items = self.items.into_iter();
|
||||
let (capacity, _) = items.size_hint();
|
||||
let mut hashed_items =
|
||||
@@ -85,8 +84,7 @@ where
|
||||
for (index, item) in items.enumerate() {
|
||||
hashed_items.insert((self.key_fn)(&item));
|
||||
let (set_index, view) = (self.view_fn)(index, item);
|
||||
rendered_items
|
||||
.push(Some((set_index, view.build(extra_attrs.clone()))));
|
||||
rendered_items.push(Some((set_index, view.build())));
|
||||
}
|
||||
KeyedState {
|
||||
parent: None,
|
||||
@@ -96,11 +94,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let KeyedState {
|
||||
parent,
|
||||
marker,
|
||||
@@ -129,7 +123,6 @@ where
|
||||
rendered_items,
|
||||
&self.view_fn,
|
||||
items,
|
||||
extra_attrs,
|
||||
);
|
||||
|
||||
*hashed_items = new_hashed_items;
|
||||
@@ -138,9 +131,9 @@ where
|
||||
|
||||
impl<T, I, K, KF, VF, VFS, V> AddAnyAttr for Keyed<T, I, K, KF, VF, VFS, V>
|
||||
where
|
||||
I: IntoIterator<Item = T> + Send + 'static,
|
||||
I: IntoIterator<Item = T> + Send,
|
||||
K: Eq + Hash + 'static,
|
||||
KF: Fn(&T) -> K + Send + 'static,
|
||||
KF: Fn(&T) -> K + Send,
|
||||
V: RenderHtml,
|
||||
V: 'static,
|
||||
VF: Fn(usize, T) -> (VFS, V) + Send + 'static,
|
||||
@@ -191,38 +184,29 @@ where
|
||||
|
||||
impl<T, I, K, KF, VF, VFS, V> RenderHtml for Keyed<T, I, K, KF, VF, VFS, V>
|
||||
where
|
||||
I: IntoIterator<Item = T> + Send + 'static,
|
||||
I: IntoIterator<Item = T> + Send,
|
||||
K: Eq + Hash + 'static,
|
||||
KF: Fn(&T) -> K + Send + 'static,
|
||||
KF: Fn(&T) -> K + Send,
|
||||
V: RenderHtml + 'static,
|
||||
VF: Fn(usize, T) -> (VFS, V) + Send + 'static,
|
||||
VFS: Fn(usize) + 'static,
|
||||
T: 'static,
|
||||
{
|
||||
type AsyncOutput = Vec<V::AsyncOutput>; // TODO
|
||||
type Owned = Keyed<T, I, K, KF, VF, VFS, V>;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {
|
||||
fn dry_resolve(&mut self) {
|
||||
// TODO...
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
batch_resolve_items_with_extra_attrs(
|
||||
self.items
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, item)| {
|
||||
let (_, view) = (self.view_fn)(index, item);
|
||||
view
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
extra_attrs,
|
||||
)
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
futures::future::join_all(self.items.into_iter().enumerate().map(
|
||||
|(index, item)| {
|
||||
let (_, view) = (self.view_fn)(index, item);
|
||||
view.resolve()
|
||||
},
|
||||
))
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>()
|
||||
@@ -234,7 +218,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
for (index, item) in self.items.into_iter().enumerate() {
|
||||
let (_, item) = (self.view_fn)(index, item);
|
||||
@@ -256,7 +240,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
for (index, item) in self.items.into_iter().enumerate() {
|
||||
let (_, item) = (self.view_fn)(index, item);
|
||||
@@ -276,7 +260,6 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
// get parent and position
|
||||
let current = cursor.current();
|
||||
@@ -298,11 +281,7 @@ where
|
||||
for (index, item) in items.enumerate() {
|
||||
hashed_items.insert((self.key_fn)(&item));
|
||||
let (set_index, view) = (self.view_fn)(index, item);
|
||||
let item = view.hydrate::<FROM_SERVER>(
|
||||
cursor,
|
||||
position,
|
||||
extra_attrs.clone(),
|
||||
);
|
||||
let item = view.hydrate::<FROM_SERVER>(cursor, position);
|
||||
rendered_items.push(Some((set_index, item)));
|
||||
}
|
||||
let marker = cursor.next_placeholder(position);
|
||||
@@ -313,10 +292,6 @@ where
|
||||
rendered_items,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, VFS, V> Mountable for KeyedState<K, VFS, V>
|
||||
@@ -356,6 +331,14 @@ where
|
||||
})
|
||||
.unwrap_or_else(|| self.marker.insert_before_this(child))
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
self.rendered_items
|
||||
.iter()
|
||||
.flatten()
|
||||
.flat_map(|item| item.1.elements())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
trait VecExt<T> {
|
||||
@@ -544,7 +527,6 @@ fn apply_diff<T, VFS, V>(
|
||||
children: &mut Vec<Option<(VFS, V::State)>>,
|
||||
view_fn: impl Fn(usize, T) -> (VFS, V),
|
||||
mut items: Vec<Option<T>>,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) where
|
||||
VFS: Fn(usize),
|
||||
V: Render,
|
||||
@@ -618,7 +600,7 @@ fn apply_diff<T, VFS, V>(
|
||||
for DiffOpAdd { at, mode } in add_cmds {
|
||||
let item = items[at].take().unwrap();
|
||||
let (set_index, item) = view_fn(at, item);
|
||||
let mut item = item.build(extra_attrs.clone());
|
||||
let mut item = item.build();
|
||||
|
||||
match mode {
|
||||
DiffOpAddMode::Normal => {
|
||||
@@ -729,7 +711,7 @@ mod tests {
|
||||
#[test]
|
||||
fn keyed_creates_list() {
|
||||
let el = ul((), keyed(1..=3, |k| *k, item));
|
||||
let el_state = el.build(None);
|
||||
let el_state = el.build();
|
||||
assert_eq!(
|
||||
el_state.el.to_debug_html(),
|
||||
"<ul><li>1</li><li>2</li><li>3</li></ul>"
|
||||
@@ -739,7 +721,7 @@ mod tests {
|
||||
#[test]
|
||||
fn adding_items_updates_list() {
|
||||
let el = ul((), keyed(1..=3, |k| *k, item));
|
||||
let mut el_state = el.build(None);
|
||||
let mut el_state = el.build();
|
||||
let el = ul((), keyed(1..=5, |k| *k, item));
|
||||
el.rebuild(&mut el_state);
|
||||
assert_eq!(
|
||||
@@ -751,7 +733,7 @@ mod tests {
|
||||
#[test]
|
||||
fn removing_items_updates_list() {
|
||||
let el = ul((), keyed(1..=3, |k| *k, item));
|
||||
let mut el_state = el.build(None);
|
||||
let mut el_state = el.build();
|
||||
let el = ul((), keyed(1..=2, |k| *k, item));
|
||||
el.rebuild(&mut el_state);
|
||||
assert_eq!(
|
||||
@@ -763,7 +745,7 @@ mod tests {
|
||||
#[test]
|
||||
fn swapping_items_updates_list() {
|
||||
let el = ul((), keyed([1, 2, 3, 4, 5], |k| *k, item));
|
||||
let mut el_state = el.build(None);
|
||||
let mut el_state = el.build();
|
||||
let el = ul((), keyed([1, 4, 3, 2, 5], |k| *k, item));
|
||||
el.rebuild(&mut el_state);
|
||||
assert_eq!(
|
||||
@@ -775,7 +757,7 @@ mod tests {
|
||||
#[test]
|
||||
fn swapping_and_removing_orders_correctly() {
|
||||
let el = ul((), keyed([1, 2, 3, 4, 5], |k| *k, item));
|
||||
let mut el_state = el.build(None);
|
||||
let mut el_state = el.build();
|
||||
let el = ul((), keyed([1, 4, 3, 5], |k| *k, item));
|
||||
el.rebuild(&mut el_state);
|
||||
assert_eq!(
|
||||
@@ -787,7 +769,7 @@ mod tests {
|
||||
#[test]
|
||||
fn arbitrarily_hard_adjustment() {
|
||||
let el = ul((), keyed([1, 2, 3, 4, 5], |k| *k, item));
|
||||
let mut el_state = el.build(None);
|
||||
let mut el_state = el.build();
|
||||
let el = ul((), keyed([2, 4, 3], |k| *k, item));
|
||||
el.rebuild(&mut el_state);
|
||||
assert_eq!(
|
||||
@@ -799,7 +781,7 @@ mod tests {
|
||||
#[test]
|
||||
fn a_series_of_moves() {
|
||||
let el = ul((), keyed([1, 2, 3, 4, 5], |k| *k, item));
|
||||
let mut el_state = el.build(None);
|
||||
let mut el_state = el.build();
|
||||
let el = ul((), keyed([2, 4, 3], |k| *k, item));
|
||||
el.rebuild(&mut el_state);
|
||||
let el = ul((), keyed([1, 7, 5, 11, 13, 17], |k| *k, item));
|
||||
@@ -819,7 +801,7 @@ mod tests {
|
||||
#[test]
|
||||
fn clearing_works() {
|
||||
let el = ul((), keyed([1, 2, 3, 4, 5], |k| *k, item));
|
||||
let mut el_state = el.build(None);
|
||||
let mut el_state = el.build();
|
||||
let el = ul((), keyed([], |k| *k, item));
|
||||
el.rebuild(&mut el_state);
|
||||
assert_eq!(el_state.el.to_debug_html(), "<ul></ul>");
|
||||
|
||||
@@ -3,7 +3,6 @@ use crate::{
|
||||
html::attribute::any_attribute::AnyAttribute, hydration::Cursor,
|
||||
ssr::StreamBuilder,
|
||||
};
|
||||
use any_view::ExtraAttrsMut;
|
||||
use parking_lot::RwLock;
|
||||
use std::{cell::RefCell, future::Future, rc::Rc, sync::Arc};
|
||||
|
||||
@@ -41,14 +40,10 @@ pub trait Render: Sized {
|
||||
type State: Mountable;
|
||||
|
||||
/// Creates the view for the first time, without hydrating from existing HTML.
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State;
|
||||
fn build(self) -> Self::State;
|
||||
|
||||
/// Updates the view with new data.
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
);
|
||||
fn rebuild(self, state: &mut Self::State);
|
||||
}
|
||||
|
||||
pub(crate) trait MarkBranch {
|
||||
@@ -104,9 +99,6 @@ where
|
||||
/// The type of the view after waiting for all asynchronous data to load.
|
||||
type AsyncOutput: RenderHtml;
|
||||
|
||||
/// A static version of this type.
|
||||
type Owned: RenderHtml + 'static;
|
||||
|
||||
/// The minimum length of HTML created when this view is rendered.
|
||||
const MIN_LENGTH: usize;
|
||||
|
||||
@@ -116,20 +108,17 @@ where
|
||||
/// “Runs” the view without other side effects. For primitive types, this is a no-op. For
|
||||
/// reactive types, this can be used to gather data about reactivity or about asynchronous data
|
||||
/// that needs to be loaded.
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>);
|
||||
fn dry_resolve(&mut self);
|
||||
|
||||
/// Waits for any asynchronous sections of the view to load and returns the output.
|
||||
fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> impl Future<Output = Self::AsyncOutput> + Send;
|
||||
fn resolve(self) -> impl Future<Output = Self::AsyncOutput> + Send;
|
||||
|
||||
/// An estimated length for this view, when rendered to HTML.
|
||||
///
|
||||
/// This is used for calculating the string buffer size when rendering HTML. It does not need
|
||||
/// to be precise, but should be an appropriate estimate. The more accurate, the fewer
|
||||
/// reallocations will be required and the faster server-side rendering will be.
|
||||
fn html_len(&self, _extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
Self::MIN_LENGTH
|
||||
}
|
||||
|
||||
@@ -138,13 +127,13 @@ where
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut buf = String::with_capacity(self.html_len(None));
|
||||
let mut buf = String::with_capacity(self.html_len());
|
||||
self.to_html_with_buf(
|
||||
&mut buf,
|
||||
&mut Position::FirstChild,
|
||||
true,
|
||||
false,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
buf
|
||||
}
|
||||
@@ -156,13 +145,13 @@ where
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut buf = String::with_capacity(self.html_len(None));
|
||||
let mut buf = String::with_capacity(self.html_len());
|
||||
self.to_html_with_buf(
|
||||
&mut buf,
|
||||
&mut Position::FirstChild,
|
||||
true,
|
||||
true,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
buf
|
||||
}
|
||||
@@ -172,14 +161,13 @@ where
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut builder =
|
||||
StreamBuilder::with_capacity(self.html_len(None), None);
|
||||
let mut builder = StreamBuilder::with_capacity(self.html_len(), None);
|
||||
self.to_html_async_with_buf::<false>(
|
||||
&mut builder,
|
||||
&mut Position::FirstChild,
|
||||
true,
|
||||
false,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
builder.finish()
|
||||
}
|
||||
@@ -191,14 +179,13 @@ where
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut builder =
|
||||
StreamBuilder::with_capacity(self.html_len(None), None);
|
||||
let mut builder = StreamBuilder::with_capacity(self.html_len(), None);
|
||||
self.to_html_async_with_buf::<false>(
|
||||
&mut builder,
|
||||
&mut Position::FirstChild,
|
||||
true,
|
||||
true,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
builder.finish()
|
||||
}
|
||||
@@ -210,14 +197,14 @@ where
|
||||
{
|
||||
//let capacity = self.html_len();
|
||||
let mut builder =
|
||||
StreamBuilder::with_capacity(self.html_len(None), Some(vec![0]));
|
||||
StreamBuilder::with_capacity(self.html_len(), Some(vec![0]));
|
||||
|
||||
self.to_html_async_with_buf::<true>(
|
||||
&mut builder,
|
||||
&mut Position::FirstChild,
|
||||
true,
|
||||
false,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
builder.finish()
|
||||
}
|
||||
@@ -230,14 +217,14 @@ where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut builder =
|
||||
StreamBuilder::with_capacity(self.html_len(None), Some(vec![0]));
|
||||
StreamBuilder::with_capacity(self.html_len(), Some(vec![0]));
|
||||
|
||||
self.to_html_async_with_buf::<true>(
|
||||
&mut builder,
|
||||
&mut Position::FirstChild,
|
||||
true,
|
||||
true,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
builder.finish()
|
||||
}
|
||||
@@ -249,7 +236,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
);
|
||||
|
||||
/// Renders a view into a buffer of (synchronous or asynchronous) HTML chunks.
|
||||
@@ -259,7 +246,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -285,7 +272,6 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State;
|
||||
|
||||
/// Hydrates using [`RenderHtml::hydrate`], beginning at the given element.
|
||||
@@ -310,49 +296,8 @@ where
|
||||
{
|
||||
let cursor = Cursor::new(el.clone());
|
||||
let position = PositionState::new(position);
|
||||
self.hydrate::<FROM_SERVER>(&cursor, &position, None)
|
||||
self.hydrate::<FROM_SERVER>(&cursor, &position)
|
||||
}
|
||||
|
||||
/// Converts this view into a owned/static type.
|
||||
fn into_owned(self) -> Self::Owned;
|
||||
}
|
||||
|
||||
/// Resolving multiple children when extra_attrs exist is tricky, because the extra_attrs are potentially shared.
|
||||
///
|
||||
/// The current assumption is:
|
||||
/// - resolve() should not be run on an AnyAttribute more than once,
|
||||
/// - any of the children could resolve() the extra_attr_states
|
||||
///
|
||||
/// Therefore, if any extra_attrs exist, resolving must happen sequentially, until any of the children resolves the extra_attrs.
|
||||
/// After that, the remaining can be done in parallel, like they will be if no extra_attrs exist.
|
||||
pub(crate) async fn batch_resolve_items_with_extra_attrs<T: RenderHtml>(
|
||||
items: impl IntoIterator<Item = T>,
|
||||
mut extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> impl IntoIterator<Item = T::AsyncOutput> {
|
||||
let mut item_iter = items.into_iter();
|
||||
let mut preresolved = vec![];
|
||||
if extra_attrs.is_some() {
|
||||
// Reset resolved state to fresh if dirty:
|
||||
extra_attrs
|
||||
.as_deref_mut()
|
||||
.iter_mut()
|
||||
.for_each(|attr| attr.resolved = false);
|
||||
for item in item_iter.by_ref() {
|
||||
preresolved.push(item.resolve(extra_attrs.as_deref_mut()).await);
|
||||
// Once all resolved, can switch to parallel and not pass in extra_attrs anymore,
|
||||
// once they've already all resolved:
|
||||
if extra_attrs.iter_mut().all(|attr| attr.resolved) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
preresolved.into_iter().chain(
|
||||
futures::future::join_all(
|
||||
item_iter.map(|val| T::resolve(val, ExtraAttrsMut::default())),
|
||||
)
|
||||
.await
|
||||
.into_iter(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Allows a type to be mounted to the DOM.
|
||||
@@ -383,6 +328,9 @@ pub trait Mountable {
|
||||
child.mount(parent, marker);
|
||||
}
|
||||
}
|
||||
|
||||
/// wip
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element>;
|
||||
}
|
||||
|
||||
/// Indicates where a node should be mounted to its parent.
|
||||
@@ -418,6 +366,12 @@ where
|
||||
.map(|inner| inner.insert_before_this(child))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
self.as_ref()
|
||||
.map(|inner| inner.elements())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Mountable for Rc<RefCell<T>>
|
||||
@@ -439,6 +393,10 @@ where
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.borrow().insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
self.borrow().elements()
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows data to be added to a static template.
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use super::{
|
||||
any_view::ExtraAttrsMut, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
};
|
||||
use super::{Mountable, Position, PositionState, Render, RenderHtml};
|
||||
use crate::{
|
||||
html::attribute::any_attribute::AnyAttribute,
|
||||
hydration::Cursor,
|
||||
@@ -44,18 +41,22 @@ macro_rules! render_primitive {
|
||||
) -> bool {
|
||||
self.0.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for $child_type {
|
||||
type State = [<$child_type:camel State>];
|
||||
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let node = Rndr::create_text_node(&self.to_string());
|
||||
[<$child_type:camel State>](node, self)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, _extra_attrs: Option<Vec<AnyAttribute>>) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let [<$child_type:camel State>](node, this) = state;
|
||||
if &self != this {
|
||||
Rndr::set_text(node, &self.to_string());
|
||||
@@ -69,17 +70,16 @@ macro_rules! render_primitive {
|
||||
impl RenderHtml for $child_type
|
||||
{
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(self, _extra_attrs: ExtraAttrsMut<'_>) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
fn to_html_with_buf(self, buf: &mut String, position: &mut Position, _escape: bool, _mark_branches: bool, _extra_attrs: Option<Vec<AnyAttribute>>) {
|
||||
fn to_html_with_buf(self, buf: &mut String, position: &mut Position, _escape: bool, _mark_branches: bool, _extra_attrs: Vec<AnyAttribute>) {
|
||||
// add a comment node to separate from previous sibling, if any
|
||||
if matches!(position, Position::NextChildAfterText) {
|
||||
buf.push_str("<!>")
|
||||
@@ -92,7 +92,6 @@ macro_rules! render_primitive {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
if position.get() == Position::FirstChild {
|
||||
cursor.child();
|
||||
@@ -116,10 +115,6 @@ macro_rules! render_primitive {
|
||||
|
||||
[<$child_type:camel State>](node, self)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTemplate for $child_type {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Mountable, Position,
|
||||
PositionState, Render, RenderHtml, ToTemplate,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml, ToTemplate,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::{
|
||||
@@ -148,36 +148,27 @@ where
|
||||
{
|
||||
type State = Option<crate::renderer::types::Text>;
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
// a view state has to be returned so it can be mounted
|
||||
Some(Rndr::create_text_node(V))
|
||||
}
|
||||
|
||||
// This type is specified as static, so no rebuilding is done.
|
||||
fn rebuild(
|
||||
self,
|
||||
_state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
}
|
||||
fn rebuild(self, _state: &mut Self::State) {}
|
||||
}
|
||||
|
||||
impl<const V: &'static str> RenderHtml for Static<V> {
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = V.len();
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
// this won't actually compile because if a weird interaction because the const &'static str and
|
||||
// the RPITIT, so we just refine it to a concrete future type; this will never change in any
|
||||
// case
|
||||
#[allow(refining_impl_trait)]
|
||||
fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> std::future::Ready<Self> {
|
||||
fn resolve(self) -> std::future::Ready<Self> {
|
||||
std::future::ready(self)
|
||||
}
|
||||
|
||||
@@ -187,7 +178,7 @@ impl<const V: &'static str> RenderHtml for Static<V> {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
_mark_branches: bool,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
_extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
// add a comment node to separate from previous sibling, if any
|
||||
if matches!(position, Position::NextChildAfterText) {
|
||||
@@ -208,7 +199,6 @@ impl<const V: &'static str> RenderHtml for Static<V> {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
if position.get() == Position::FirstChild {
|
||||
cursor.child();
|
||||
@@ -231,10 +221,6 @@ impl<const V: &'static str> RenderHtml for Static<V> {
|
||||
|
||||
Some(node)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<const V: &'static str> AddAnyAttr for Static<V> {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use super::{
|
||||
any_view::ExtraAttrsMut, Mountable, Position, PositionState, Render,
|
||||
RenderHtml, ToTemplate,
|
||||
Mountable, Position, PositionState, Render, RenderHtml, ToTemplate,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::any_attribute::AnyAttribute,
|
||||
@@ -24,16 +23,12 @@ pub struct StrState<'a> {
|
||||
impl<'a> Render for &'a str {
|
||||
type State = StrState<'a>;
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let node = Rndr::create_text_node(self);
|
||||
StrState { node, str: self }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let StrState { node, str } = state;
|
||||
if &self != str {
|
||||
Rndr::set_text(node, self);
|
||||
@@ -44,20 +39,16 @@ impl<'a> Render for &'a str {
|
||||
|
||||
impl RenderHtml for &str {
|
||||
type AsyncOutput = Self;
|
||||
type Owned = String;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
fn html_len(&self, _extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
@@ -67,7 +58,7 @@ impl RenderHtml for &str {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
_mark_branches: bool,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
_extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
// add a comment node to separate from previous sibling, if any
|
||||
if matches!(position, Position::NextChildAfterText) {
|
||||
@@ -88,7 +79,6 @@ impl RenderHtml for &str {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
if position.get() == Position::FirstChild {
|
||||
cursor.child();
|
||||
@@ -114,10 +104,6 @@ impl RenderHtml for &str {
|
||||
|
||||
StrState { node, str: self }
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTemplate for &str {
|
||||
@@ -154,6 +140,10 @@ impl Mountable for StrState<'_> {
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.node.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
/// Retained view state for `String`.
|
||||
@@ -165,16 +155,12 @@ pub struct StringState {
|
||||
impl Render for String {
|
||||
type State = StringState;
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let node = Rndr::create_text_node(&self);
|
||||
StringState { node, str: self }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let StringState { node, str } = state;
|
||||
if &self != str {
|
||||
Rndr::set_text(node, &self);
|
||||
@@ -186,18 +172,14 @@ impl Render for String {
|
||||
impl RenderHtml for String {
|
||||
const MIN_LENGTH: usize = 0;
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
fn html_len(&self, _extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
@@ -207,7 +189,7 @@ impl RenderHtml for String {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
<&str as RenderHtml>::to_html_with_buf(
|
||||
self.as_str(),
|
||||
@@ -223,17 +205,11 @@ impl RenderHtml for String {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let StrState { node, .. } =
|
||||
self.as_str()
|
||||
.hydrate::<FROM_SERVER>(cursor, position, extra_attrs);
|
||||
self.as_str().hydrate::<FROM_SERVER>(cursor, position);
|
||||
StringState { node, str: self }
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTemplate for String {
|
||||
@@ -268,6 +244,10 @@ impl Mountable for StringState {
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.node.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
/// Retained view state for `Rc<str>`.
|
||||
@@ -279,16 +259,12 @@ pub struct RcStrState {
|
||||
impl Render for Rc<str> {
|
||||
type State = RcStrState;
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let node = Rndr::create_text_node(&self);
|
||||
RcStrState { node, str: self }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let RcStrState { node, str } = state;
|
||||
if !Rc::ptr_eq(&self, str) {
|
||||
Rndr::set_text(node, &self);
|
||||
@@ -308,11 +284,11 @@ where
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
async fn resolve(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
fn html_len(&self, _extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
@@ -324,7 +300,6 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let this: &str = self.as_ref();
|
||||
let StrState { node, .. } =
|
||||
@@ -365,6 +340,10 @@ impl Mountable for RcStrState {
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.node.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
/// Retained view state for `Arc<str>`.
|
||||
@@ -376,16 +355,12 @@ pub struct ArcStrState {
|
||||
impl Render for Arc<str> {
|
||||
type State = ArcStrState;
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let node = Rndr::create_text_node(&self);
|
||||
ArcStrState { node, str: self }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let ArcStrState { node, str } = state;
|
||||
if !Arc::ptr_eq(&self, str) {
|
||||
Rndr::set_text(node, &self);
|
||||
@@ -396,20 +371,16 @@ impl Render for Arc<str> {
|
||||
|
||||
impl RenderHtml for Arc<str> {
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Arc<str>;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
fn html_len(&self, _extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
@@ -419,7 +390,7 @@ impl RenderHtml for Arc<str> {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
<&str as RenderHtml>::to_html_with_buf(
|
||||
&self,
|
||||
@@ -435,17 +406,12 @@ impl RenderHtml for Arc<str> {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let this: &str = self.as_ref();
|
||||
let StrState { node, .. } =
|
||||
this.hydrate::<FROM_SERVER>(cursor, position, extra_attrs);
|
||||
this.hydrate::<FROM_SERVER>(cursor, position);
|
||||
ArcStrState { node, str: self }
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTemplate for Arc<str> {
|
||||
@@ -480,6 +446,10 @@ impl Mountable for ArcStrState {
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.node.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
/// Retained view state for `Cow<'_, str>`.
|
||||
@@ -491,16 +461,12 @@ pub struct CowStrState<'a> {
|
||||
impl<'a> Render for Cow<'a, str> {
|
||||
type State = CowStrState<'a>;
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let node = Rndr::create_text_node(&self);
|
||||
CowStrState { node, str: self }
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let CowStrState { node, str } = state;
|
||||
if self != *str {
|
||||
Rndr::set_text(node, &self);
|
||||
@@ -511,20 +477,16 @@ impl<'a> Render for Cow<'a, str> {
|
||||
|
||||
impl RenderHtml for Cow<'_, str> {
|
||||
type AsyncOutput = Self;
|
||||
type Owned = String;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self
|
||||
}
|
||||
|
||||
fn html_len(&self, _extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
@@ -534,7 +496,7 @@ impl RenderHtml for Cow<'_, str> {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
<&str as RenderHtml>::to_html_with_buf(
|
||||
&self,
|
||||
@@ -550,17 +512,12 @@ impl RenderHtml for Cow<'_, str> {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
let this: &str = self.as_ref();
|
||||
let StrState { node, .. } =
|
||||
this.hydrate::<FROM_SERVER>(cursor, position, extra_attrs);
|
||||
this.hydrate::<FROM_SERVER>(cursor, position);
|
||||
CowStrState { node, str: self }
|
||||
}
|
||||
|
||||
fn into_owned(self) -> <Self as RenderHtml>::Owned {
|
||||
self.into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTemplate for Cow<'_, str> {
|
||||
@@ -595,4 +552,8 @@ impl Mountable for CowStrState<'_> {
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.node.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Mountable, Position,
|
||||
PositionState, Render, RenderHtml, ToTemplate,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml, ToTemplate,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::{any_attribute::AnyAttribute, Attribute},
|
||||
@@ -40,22 +40,15 @@ where
|
||||
|
||||
// TODO try_build/try_rebuild()
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
let tpl = Self::to_template();
|
||||
let contents = Rndr::clone_template(&tpl);
|
||||
self.view.hydrate::<false>(
|
||||
&Cursor::new(contents),
|
||||
&Default::default(),
|
||||
extra_attrs,
|
||||
)
|
||||
self.view
|
||||
.hydrate::<false>(&Cursor::new(contents), &Default::default())
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
self.view.rebuild(state, extra_attrs)
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
self.view.rebuild(state)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +76,6 @@ where
|
||||
V::State: Mountable,
|
||||
{
|
||||
type AsyncOutput = V::AsyncOutput;
|
||||
type Owned = V::Owned;
|
||||
|
||||
const MIN_LENGTH: usize = V::MIN_LENGTH;
|
||||
|
||||
@@ -93,7 +85,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
self.view.to_html_with_buf(
|
||||
buf,
|
||||
@@ -108,25 +100,16 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
self.view
|
||||
.hydrate::<FROM_SERVER>(cursor, position, extra_attrs)
|
||||
self.view.hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
self.view.dry_resolve(extra_attrs);
|
||||
fn dry_resolve(&mut self) {
|
||||
self.view.dry_resolve();
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
self.view.resolve(extra_attrs).await
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self.view.into_owned()
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
self.view.resolve().await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use super::{
|
||||
any_view::ExtraAttrsMut, Mountable, Position, PositionState, Render,
|
||||
RenderHtml, ToTemplate,
|
||||
Mountable, Position, PositionState, Render, RenderHtml, ToTemplate,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::{any_attribute::AnyAttribute, Attribute},
|
||||
@@ -15,21 +14,15 @@ use const_str_slice_concat::{
|
||||
impl Render for () {
|
||||
type State = crate::renderer::types::Placeholder;
|
||||
|
||||
fn build(self, _extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
Rndr::create_placeholder()
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
_state: &mut Self::State,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
}
|
||||
fn rebuild(self, _state: &mut Self::State) {}
|
||||
}
|
||||
|
||||
impl RenderHtml for () {
|
||||
type AsyncOutput = ();
|
||||
type Owned = ();
|
||||
|
||||
const MIN_LENGTH: usize = 3;
|
||||
const EXISTS: bool = false;
|
||||
@@ -40,7 +33,7 @@ impl RenderHtml for () {
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
_mark_branches: bool,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
_extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
if escape {
|
||||
buf.push_str("<!>");
|
||||
@@ -52,20 +45,13 @@ impl RenderHtml for () {
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
_extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
cursor.next_placeholder(position)
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
_extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
}
|
||||
async fn resolve(self) -> Self::AsyncOutput {}
|
||||
|
||||
fn dry_resolve(&mut self, _extra_attrs: ExtraAttrsMut<'_>) {}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {}
|
||||
fn dry_resolve(&mut self) {}
|
||||
}
|
||||
|
||||
impl AddAnyAttr for () {
|
||||
@@ -94,6 +80,10 @@ impl Mountable for () {
|
||||
fn insert_before_this(&self, _child: &mut dyn Mountable) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTemplate for () {
|
||||
@@ -113,16 +103,12 @@ impl ToTemplate for () {
|
||||
impl<A: Render> Render for (A,) {
|
||||
type State = A::State;
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
self.0.build(extra_attrs)
|
||||
fn build(self) -> Self::State {
|
||||
self.0.build()
|
||||
}
|
||||
|
||||
fn rebuild(
|
||||
self,
|
||||
state: &mut Self::State,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) {
|
||||
self.0.rebuild(state, extra_attrs)
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
self.0.rebuild(state)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,12 +117,11 @@ where
|
||||
A: RenderHtml,
|
||||
{
|
||||
type AsyncOutput = (A::AsyncOutput,);
|
||||
type Owned = (A::Owned,);
|
||||
|
||||
const MIN_LENGTH: usize = A::MIN_LENGTH;
|
||||
|
||||
fn html_len(&self, extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
self.0.html_len(extra_attrs)
|
||||
fn html_len(&self) -> usize {
|
||||
self.0.html_len()
|
||||
}
|
||||
|
||||
fn to_html_with_buf(
|
||||
@@ -145,7 +130,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
self.0.to_html_with_buf(
|
||||
buf,
|
||||
@@ -162,7 +147,7 @@ where
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
extra_attrs: Vec<AnyAttribute>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -179,24 +164,16 @@ where
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
extra_attrs: Option<Vec<AnyAttribute>>,
|
||||
) -> Self::State {
|
||||
self.0.hydrate::<FROM_SERVER>(cursor, position, extra_attrs)
|
||||
self.0.hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
self,
|
||||
extra_attrs: ExtraAttrsMut<'_>,
|
||||
) -> Self::AsyncOutput {
|
||||
(self.0.resolve(extra_attrs).await,)
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
(self.0.resolve().await,)
|
||||
}
|
||||
|
||||
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
|
||||
self.0.dry_resolve(extra_attrs);
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
(self.0.into_owned(),)
|
||||
fn dry_resolve(&mut self) {
|
||||
self.0.dry_resolve();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,21 +221,21 @@ macro_rules! impl_view_for_tuples {
|
||||
type State = ($first::State, $($ty::State,)*);
|
||||
|
||||
|
||||
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn build(self) -> Self::State {
|
||||
#[allow(non_snake_case)]
|
||||
let ($first, $($ty,)*) = self;
|
||||
(
|
||||
$first.build(extra_attrs.clone()),
|
||||
$($ty.build(extra_attrs.clone())),*
|
||||
$first.build(),
|
||||
$($ty.build()),*
|
||||
)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, extra_attrs: Option<Vec<AnyAttribute>>) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
paste::paste! {
|
||||
let ([<$first:lower>], $([<$ty:lower>],)*) = self;
|
||||
let ([<view_ $first:lower>], $([<view_ $ty:lower>],)*) = state;
|
||||
[<$first:lower>].rebuild([<view_ $first:lower>], extra_attrs.clone());
|
||||
$([<$ty:lower>].rebuild([<view_ $ty:lower>], extra_attrs.clone()));*
|
||||
[<$first:lower>].rebuild([<view_ $first:lower>]);
|
||||
$([<$ty:lower>].rebuild([<view_ $ty:lower>]));*
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,18 +247,24 @@ macro_rules! impl_view_for_tuples {
|
||||
|
||||
{
|
||||
type AsyncOutput = ($first::AsyncOutput, $($ty::AsyncOutput,)*);
|
||||
type Owned = ($first::Owned, $($ty::Owned,)*);
|
||||
|
||||
const MIN_LENGTH: usize = $first::MIN_LENGTH $(+ $ty::MIN_LENGTH)*;
|
||||
|
||||
#[inline(always)]
|
||||
fn html_len(&self, extra_attrs: Option<Vec<&AnyAttribute>>) -> usize {
|
||||
fn html_len(&self) -> usize {
|
||||
#[allow(non_snake_case)]
|
||||
let ($first, $($ty,)* ) = self;
|
||||
$($ty.html_len(extra_attrs.clone()) +)* $first.html_len(extra_attrs.clone())
|
||||
$($ty.html_len() +)* $first.html_len()
|
||||
}
|
||||
|
||||
fn to_html_with_buf(self, buf: &mut String, position: &mut Position, escape: bool, mark_branches: bool, extra_attrs: Option<Vec<AnyAttribute>>) {
|
||||
fn to_html_with_buf(
|
||||
self,
|
||||
buf: &mut String,
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Vec<AnyAttribute>
|
||||
) {
|
||||
#[allow(non_snake_case)]
|
||||
let ($first, $($ty,)* ) = self;
|
||||
$first.to_html_with_buf(buf, position, escape, mark_branches, extra_attrs.clone());
|
||||
@@ -290,7 +273,12 @@ macro_rules! impl_view_for_tuples {
|
||||
|
||||
fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
|
||||
self,
|
||||
buf: &mut StreamBuilder, position: &mut Position, escape: bool, mark_branches: bool, extra_attrs: Option<Vec<AnyAttribute>>) where
|
||||
buf: &mut StreamBuilder,
|
||||
position: &mut Position,
|
||||
escape: bool,
|
||||
mark_branches: bool,
|
||||
extra_attrs: Vec<AnyAttribute>
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
#[allow(non_snake_case)]
|
||||
@@ -299,47 +287,30 @@ macro_rules! impl_view_for_tuples {
|
||||
$($ty.to_html_async_with_buf::<OUT_OF_ORDER>(buf, position, escape, mark_branches, extra_attrs.clone()));*
|
||||
}
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(self, cursor: &Cursor, position: &PositionState, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
|
||||
fn hydrate<const FROM_SERVER: bool>(self, cursor: &Cursor, position: &PositionState) -> Self::State {
|
||||
#[allow(non_snake_case)]
|
||||
let ($first, $($ty,)* ) = self;
|
||||
(
|
||||
$first.hydrate::<FROM_SERVER>(cursor, position, extra_attrs.clone()),
|
||||
$($ty.hydrate::<FROM_SERVER>(cursor, position, extra_attrs.clone())),*
|
||||
$first.hydrate::<FROM_SERVER>(cursor, position),
|
||||
$($ty.hydrate::<FROM_SERVER>(cursor, position)),*
|
||||
)
|
||||
}
|
||||
|
||||
async fn resolve(self, mut extra_attrs: ExtraAttrsMut<'_>) -> Self::AsyncOutput {
|
||||
async fn resolve(self) -> Self::AsyncOutput {
|
||||
#[allow(non_snake_case)]
|
||||
let ($first, $($ty,)*) = self;
|
||||
if extra_attrs.is_some() {
|
||||
// TODO: any good way to make this only partially sequantial like with batch_resolve_items_with_extra_attrs_tuples_inner()?
|
||||
(
|
||||
$first.resolve(extra_attrs.as_deref_mut()).await,
|
||||
$($ty.resolve(extra_attrs.as_deref_mut()).await),*
|
||||
)
|
||||
} else {
|
||||
futures::join!(
|
||||
$first.resolve(ExtraAttrsMut::default()),
|
||||
$($ty.resolve(ExtraAttrsMut::default())),*
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn dry_resolve(&mut self, mut extra_attrs: ExtraAttrsMut<'_>) {
|
||||
#[allow(non_snake_case)]
|
||||
let ($first, $($ty,)*) = self;
|
||||
$first.dry_resolve(extra_attrs.as_deref_mut());
|
||||
$($ty.dry_resolve(extra_attrs.as_deref_mut()));*
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
#[allow(non_snake_case)]
|
||||
let ($first, $($ty,)*) = self;
|
||||
(
|
||||
$first.into_owned(),
|
||||
$($ty.into_owned()),*
|
||||
futures::join!(
|
||||
$first.resolve(),
|
||||
$($ty.resolve()),*
|
||||
)
|
||||
}
|
||||
|
||||
fn dry_resolve(&mut self) {
|
||||
#[allow(non_snake_case)]
|
||||
let ($first, $($ty,)*) = self;
|
||||
$first.dry_resolve();
|
||||
$($ty.dry_resolve());*
|
||||
}
|
||||
}
|
||||
|
||||
impl<$first, $($ty),*> ToTemplate for ($first, $($ty,)*)
|
||||
@@ -394,6 +365,14 @@ macro_rules! impl_view_for_tuples {
|
||||
$first.insert_before_this(child)
|
||||
$(|| $ty.insert_before_this(child))*
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
#[allow(non_snake_case)] // better macro performance
|
||||
let ($first, $($ty,)*) = self;
|
||||
$first.elements().into_iter()
|
||||
$(.chain($ty.elements()))*
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<$first, $($ty,)*> AddAnyAttr for ($first, $($ty,)*)
|
||||
|
||||
Reference in New Issue
Block a user