Skip to content

Commit

Permalink
implement AddAnyAttr for AnyView (#3562)
Browse files Browse the repository at this point in the history
  • Loading branch information
gbj authored Feb 10, 2025
1 parent 287fc47 commit 299acd2
Show file tree
Hide file tree
Showing 38 changed files with 1,419 additions and 2,178 deletions.
493 changes: 231 additions & 262 deletions Cargo.lock

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions examples/counter/tests/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand All @@ -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
Expand Down Expand Up @@ -150,7 +150,7 @@ async fn inc() {
}
}
.into_view()
.build(None)
.build()
.outer_html()
);

Expand All @@ -173,7 +173,7 @@ async fn inc() {
}
}
.into_view()
.build(None)
.build()
.outer_html()
);
}
45 changes: 13 additions & 32 deletions leptos/src/attribute_interceptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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,
{
Expand Down Expand Up @@ -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(
Expand All @@ -144,32 +135,22 @@ 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![],
)
}

fn hydrate<const FROM_SERVER: bool>(
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)
}
}
71 changes: 27 additions & 44 deletions leptos/src/error_boundary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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>
Expand All @@ -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>,
Expand All @@ -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
Expand All @@ -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,
Expand All @@ -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();
Expand Down Expand Up @@ -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,
Expand All @@ -300,7 +297,7 @@ where
hook,
boundary_id,
errors_empty,
children: children.resolve(extra_attrs).await,
children: children.resolve().await,
fallback,
errors,
}
Expand All @@ -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);
Expand Down Expand Up @@ -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,
{
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand All @@ -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),
),
)
};
Expand All @@ -450,10 +437,6 @@ where
},
)
}

fn into_owned(self) -> Self::Owned {
self
}
}

#[derive(Debug)]
Expand Down
Loading

0 comments on commit 299acd2

Please sign in to comment.