Skip to content

Commit

Permalink
AddAnyAttr static (#3553)
Browse files Browse the repository at this point in the history
  • Loading branch information
zakstucke authored Feb 6, 2025
1 parent 597175a commit 8f74a6d
Show file tree
Hide file tree
Showing 37 changed files with 2,497 additions and 1,018 deletions.
493 changes: 262 additions & 231 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() will actually build the DOM elements
.build()
// .build() returned an ElementState, which is a smart pointer for
// calling .build(None) will actually build the DOM elements
.build(None)
// .build(None) 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()
.build(None)
.outer_html()
);

Expand All @@ -173,7 +173,7 @@ async fn inc() {
}
}
.into_view()
.build()
.build(None)
.outer_html()
);
}
51 changes: 38 additions & 13 deletions leptos/src/attribute_interceptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ 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 @@ -43,7 +44,7 @@ pub fn AttributeInterceptor<Chil, T>(
) -> impl IntoView
where
Chil: Fn(AnyAttribute) -> T + Send + Sync + 'static,
T: IntoView,
T: IntoView + 'static,
{
AttributeInterceptorInner::new(children)
}
Expand Down Expand Up @@ -77,16 +78,20 @@ impl<T: IntoView> AttributeInterceptorInner<T, ()> {
impl<T: IntoView, A: Attribute> Render for AttributeInterceptorInner<T, A> {
type State = <T as Render>::State;

fn build(self) -> Self::State {
self.children.build()
fn build(self, extra_attrs: Option<Vec<AnyAttribute>>) -> Self::State {
self.children.build(extra_attrs)
}

fn rebuild(self, state: &mut Self::State) {
self.children.rebuild(state);
fn rebuild(
self,
state: &mut Self::State,
extra_attrs: Option<Vec<AnyAttribute>>,
) {
self.children.rebuild(state, extra_attrs);
}
}

impl<T: IntoView, A> AddAnyAttr for AttributeInterceptorInner<T, A>
impl<T: IntoView + 'static, A> AddAnyAttr for AttributeInterceptorInner<T, A>
where
A: Attribute,
{
Expand Down Expand Up @@ -114,19 +119,23 @@ where
}
}

impl<T: IntoView, A: Attribute> RenderHtml for AttributeInterceptorInner<T, A> {
impl<T: IntoView + 'static, 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) {
self.children.dry_resolve()
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
self.children.dry_resolve(extra_attrs)
}

fn resolve(
self,
extra_attrs: ExtraAttrsMut<'_>,
) -> impl std::future::Future<Output = Self::AsyncOutput> + Send {
self.children.resolve()
self.children.resolve(extra_attrs)
}

fn to_html_with_buf(
Expand All @@ -135,16 +144,32 @@ impl<T: IntoView, A: Attribute> RenderHtml for AttributeInterceptorInner<T, A> {
position: &mut leptos::tachys::view::Position,
escape: bool,
mark_branches: bool,
extra_attrs: Option<Vec<AnyAttribute>>,
) {
self.children
.to_html_with_buf(buf, position, escape, mark_branches)
self.children.to_html_with_buf(
buf,
position,
escape,
mark_branches,
extra_attrs,
)
}

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)
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(),
}
}
}
67 changes: 49 additions & 18 deletions leptos/src/error_boundary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ use reactive_graph::{
use rustc_hash::FxHashMap;
use std::{fmt::Debug, sync::Arc};
use tachys::{
html::attribute::Attribute,
html::attribute::{any_attribute::AnyAttribute, Attribute},
hydration::Cursor,
reactive_graph::OwnedView,
ssr::StreamBuilder,
view::{
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
RenderHtml,
add_attr::AddAnyAttr, any_view::ExtraAttrsMut, Mountable, Position,
PositionState, Render, RenderHtml,
},
};
use throw_error::{Error, ErrorHook, ErrorId};
Expand Down Expand Up @@ -173,10 +173,10 @@ where
{
type State = RenderEffect<ErrorBoundaryViewState<Chil::State, Fal::State>>;

fn build(mut self) -> Self::State {
fn build(mut self, extra_attrs: Option<Vec<AnyAttribute>>) -> 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());
let mut children = Some(self.children.build(extra_attrs.clone()));
RenderEffect::new(
move |prev: Option<
ErrorBoundaryViewState<Chil::State, Fal::State>,
Expand All @@ -193,7 +193,8 @@ where
// yes errors, and was showing children
(false, None) => {
state.fallback = Some(
(self.fallback)(self.errors.clone()).build(),
(self.fallback)(self.errors.clone())
.build(extra_attrs.clone()),
);
state
.children
Expand All @@ -207,8 +208,10 @@ where
}
state
} else {
let fallback = (!self.errors_empty.get())
.then(|| (self.fallback)(self.errors.clone()).build());
let fallback = (!self.errors_empty.get()).then(|| {
(self.fallback)(self.errors.clone())
.build(extra_attrs.clone())
});
ErrorBoundaryViewState {
children: children.take().unwrap(),
fallback,
Expand All @@ -218,8 +221,12 @@ where
)
}

fn rebuild(self, state: &mut Self::State) {
let new = self.build();
fn rebuild(
self,
state: &mut Self::State,
extra_attrs: Option<Vec<AnyAttribute>>,
) {
let new = self.build(extra_attrs);
let mut old = std::mem::replace(state, new);
old.insert_before_this(state);
old.unmount();
Expand Down Expand Up @@ -268,14 +275,18 @@ 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) {
self.children.dry_resolve();
fn dry_resolve(&mut self, extra_attrs: ExtraAttrsMut<'_>) {
self.children.dry_resolve(extra_attrs);
}

async fn resolve(self) -> Self::AsyncOutput {
async fn resolve(
self,
extra_attrs: ExtraAttrsMut<'_>,
) -> Self::AsyncOutput {
let ErrorBoundaryView {
hook,
boundary_id,
Expand All @@ -289,7 +300,7 @@ where
hook,
boundary_id,
errors_empty,
children: children.resolve().await,
children: children.resolve(extra_attrs).await,
fallback,
errors,
}
Expand All @@ -301,6 +312,7 @@ where
position: &mut Position,
escape: bool,
mark_branches: bool,
extra_attrs: Option<Vec<AnyAttribute>>,
) {
// first, attempt to serialize the children to HTML, then check for errors
let _hook = throw_error::set_error_hook(self.hook);
Expand All @@ -311,6 +323,7 @@ where
&mut new_pos,
escape,
mark_branches,
extra_attrs.clone(),
);

// any thrown errors would've been caught here
Expand All @@ -323,6 +336,7 @@ where
position,
escape,
mark_branches,
extra_attrs,
);
}
}
Expand All @@ -333,6 +347,7 @@ where
position: &mut Position,
escape: bool,
mark_branches: bool,
extra_attrs: Option<Vec<AnyAttribute>>,
) where
Self: Sized,
{
Expand All @@ -345,6 +360,7 @@ where
&mut new_pos,
escape,
mark_branches,
extra_attrs.clone(),
);

// any thrown errors would've been caught here
Expand All @@ -358,6 +374,7 @@ where
position,
escape,
mark_branches,
extra_attrs,
);
buf.push_sync(&fallback);
}
Expand All @@ -367,6 +384,7 @@ 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 @@ -388,7 +406,8 @@ where
// yes errors, and was showing children
(false, None) => {
state.fallback = Some(
(self.fallback)(self.errors.clone()).build(),
(self.fallback)(self.errors.clone())
.build(extra_attrs.clone()),
);
state
.children
Expand All @@ -405,15 +424,23 @@ where
let children = children.take().unwrap();
let (children, fallback) = if self.errors_empty.get() {
(
children.hydrate::<FROM_SERVER>(&cursor, &position),
children.hydrate::<FROM_SERVER>(
&cursor,
&position,
extra_attrs.clone(),
),
None,
)
} else {
(
children.build(),
children.build(extra_attrs.clone()),
Some(
(self.fallback)(self.errors.clone())
.hydrate::<FROM_SERVER>(&cursor, &position),
.hydrate::<FROM_SERVER>(
&cursor,
&position,
extra_attrs.clone(),
),
),
)
};
Expand All @@ -423,6 +450,10 @@ where
},
)
}

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

#[derive(Debug)]
Expand Down
Loading

0 comments on commit 8f74a6d

Please sign in to comment.