mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
full attribute spreading
This commit is contained in:
parent
9ec30d71d2
commit
e93a34a2c9
17 changed files with 395 additions and 71 deletions
|
@ -1,4 +1,5 @@
|
|||
use leptos::prelude::*;
|
||||
use leptos::tachys::html::style::style;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -65,6 +66,8 @@ pub fn fetch_example() -> impl IntoView {
|
|||
}
|
||||
};
|
||||
|
||||
let spreadable = style(("background-color", "AliceBlue"));
|
||||
|
||||
view! {
|
||||
<div>
|
||||
<label>
|
||||
|
@ -79,7 +82,7 @@ pub fn fetch_example() -> impl IntoView {
|
|||
/>
|
||||
|
||||
</label>
|
||||
<Transition fallback=|| view! { <div>"Loading..."</div> }>
|
||||
<Transition fallback=|| view! { <div>"Loading..."</div> } {..spreadable}>
|
||||
<ErrorBoundary fallback>
|
||||
<ul>
|
||||
{move || Suspend(async move {
|
||||
|
|
|
@ -47,8 +47,7 @@ pub fn App() -> impl IntoView {
|
|||
// Button C: use a regular event listener
|
||||
// setting an event listener on a component like this applies it
|
||||
// to each of the top-level elements the component returns
|
||||
// TODO WIP
|
||||
// <ButtonC on:click=move |_| set_italics.update(|value| *value = !*value)/>
|
||||
<ButtonC on:click=move |_| set_italics.update(|value| *value = !*value)/>
|
||||
|
||||
// Button D gets its setter from context rather than props
|
||||
<ButtonD/>
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
use leptos::*;
|
||||
use leptos::{
|
||||
attr::id,
|
||||
ev::{self, on},
|
||||
prelude::*,
|
||||
// TODO clean up import here
|
||||
tachys::html::class::class,
|
||||
};
|
||||
|
||||
/// Demonstrates how attributes and event handlers can be spread onto elements.
|
||||
#[component]
|
||||
|
@ -7,51 +13,55 @@ pub fn SpreadingExample() -> impl IntoView {
|
|||
let _ = window().alert_with_message(msg.as_ref());
|
||||
}
|
||||
|
||||
let attrs_only: Vec<(&'static str, Attribute)> =
|
||||
vec![("data-foo", "42".into_attribute())];
|
||||
|
||||
let event_handlers_only: Vec<EventHandlerFn> =
|
||||
vec![EventHandlerFn::Click(Box::new(|_e: ev::MouseEvent| {
|
||||
alert("event_handlers_only clicked");
|
||||
}))];
|
||||
|
||||
let combined: Vec<Binding> = vec![
|
||||
("data-foo", "123".into_attribute()).into(),
|
||||
EventHandlerFn::Click(Box::new(|_e: ev::MouseEvent| {
|
||||
// TODO support data- attributes better
|
||||
let attrs_only = class("foo");
|
||||
let event_handlers_only = on(ev::click, move |_e: ev::MouseEvent| {
|
||||
alert("event_handlers_only clicked");
|
||||
});
|
||||
let combined = (
|
||||
class("bar"),
|
||||
on(ev::click, move |_e: ev::MouseEvent| {
|
||||
alert("combined clicked");
|
||||
}))
|
||||
.into(),
|
||||
];
|
||||
|
||||
let partial_attrs: Vec<(&'static str, Attribute)> =
|
||||
vec![("data-foo", "11".into_attribute())];
|
||||
|
||||
let partial_event_handlers: Vec<EventHandlerFn> =
|
||||
vec![EventHandlerFn::Click(Box::new(|_e: ev::MouseEvent| {
|
||||
alert("partial_event_handlers clicked");
|
||||
}))];
|
||||
}),
|
||||
);
|
||||
let partial_attrs = (id("snood"), class("baz"));
|
||||
let partial_event_handlers = on(ev::click, move |_e: ev::MouseEvent| {
|
||||
alert("partial_event_handlers clicked");
|
||||
});
|
||||
|
||||
view! {
|
||||
<div {..attrs_only}>
|
||||
"<div {..attrs_only} />"
|
||||
</div>
|
||||
<p>
|
||||
"You can spread any valid attribute, including a tuple of attributes, with the {..attr} syntax"
|
||||
</p>
|
||||
<div {..attrs_only.clone()}>"<div {..attrs_only} />"</div>
|
||||
|
||||
<div {..event_handlers_only}>
|
||||
"<div {..event_handlers_only} />"
|
||||
</div>
|
||||
<div {..event_handlers_only.clone()}>"<div {..event_handlers_only} />"</div>
|
||||
|
||||
<div {..combined}>
|
||||
"<div {..combined} />"
|
||||
</div>
|
||||
<div {..combined.clone()}>"<div {..combined} />"</div>
|
||||
|
||||
<div {..partial_attrs} {..partial_event_handlers}>
|
||||
<div {..partial_attrs.clone()} {..partial_event_handlers.clone()}>
|
||||
"<div {..partial_attrs} {..partial_event_handlers} />"
|
||||
</div>
|
||||
|
||||
// Overwriting an event handler, here on:click, will result in a panic in debug builds. In release builds, the initial handler is kept.
|
||||
// If spreading is used, prefer manually merging event handlers in the binding list instead.
|
||||
//<div {..mixed} on:click=|_e| { alert("I will never be seen..."); }>
|
||||
// "with overwritten click handler"
|
||||
//</div>
|
||||
<hr/>
|
||||
|
||||
<p>
|
||||
"The .. is not required to spread; you can pass any valid attribute in a block by itself."
|
||||
</p>
|
||||
<div {attrs_only}>"<div {attrs_only} />"</div>
|
||||
|
||||
<div {event_handlers_only}>"<div {event_handlers_only} />"</div>
|
||||
|
||||
<div {combined}>"<div {combined} />"</div>
|
||||
|
||||
<div {partial_attrs} {partial_event_handlers}>
|
||||
"<div {partial_attrs} {partial_event_handlers} />"
|
||||
</div>
|
||||
}
|
||||
// TODO check below
|
||||
// Overwriting an event handler, here on:click, will result in a panic in debug builds. In release builds, the initial handler is kept.
|
||||
// If spreading is used, prefer manually merging event handlers in the binding list instead.
|
||||
//<div {..mixed} on:click=|_e| { alert("I will never be seen..."); }>
|
||||
// "with overwritten click handler"
|
||||
//</div>
|
||||
}
|
||||
|
|
|
@ -4,9 +4,5 @@ use spread::SpreadingExample;
|
|||
pub fn main() {
|
||||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
mount_to_body(|| {
|
||||
view! {
|
||||
<SpreadingExample/>
|
||||
}
|
||||
})
|
||||
mount::mount_to_body(SpreadingExample)
|
||||
}
|
||||
|
|
|
@ -10,10 +10,14 @@ use reactive_graph::{
|
|||
use rustc_hash::FxHashMap;
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
use tachys::{
|
||||
html::attribute::Attribute,
|
||||
hydration::Cursor,
|
||||
renderer::{CastFrom, Renderer},
|
||||
ssr::StreamBuilder,
|
||||
view::{Mountable, Position, PositionState, Render, RenderHtml},
|
||||
view::{
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
},
|
||||
};
|
||||
use throw_error::{Error, ErrorHook, ErrorId};
|
||||
|
||||
|
@ -193,6 +197,41 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<Chil, Fal, Rndr> AddAnyAttr<Rndr> for ErrorBoundaryView<Chil, Fal, Rndr>
|
||||
where
|
||||
Chil: RenderHtml<Rndr>,
|
||||
Fal: RenderHtml<Rndr> + Send,
|
||||
Rndr: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> =
|
||||
ErrorBoundaryView<Chil::Output<SomeNewAttr>, Fal, Rndr>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
let ErrorBoundaryView {
|
||||
boundary_id,
|
||||
errors_empty,
|
||||
children,
|
||||
fallback,
|
||||
errors,
|
||||
rndr,
|
||||
} = self;
|
||||
ErrorBoundaryView {
|
||||
boundary_id,
|
||||
errors_empty,
|
||||
children: children.add_any_attr(attr),
|
||||
fallback,
|
||||
errors,
|
||||
rndr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Chil, Fal, Rndr> RenderHtml<Rndr> for ErrorBoundaryView<Chil, Fal, Rndr>
|
||||
where
|
||||
Chil: RenderHtml<Rndr>,
|
||||
|
|
|
@ -55,7 +55,7 @@ pub fn For<Rndr, IF, I, T, EF, N, KF, K>(
|
|||
) -> impl IntoView
|
||||
where
|
||||
IF: Fn() -> I + Send + 'static,
|
||||
I: IntoIterator<Item = T> + Send,
|
||||
I: IntoIterator<Item = T> + Send + 'static,
|
||||
EF: Fn(T) -> N + Send + Clone + 'static,
|
||||
N: IntoView + 'static,
|
||||
KF: Fn(&T) -> K + Send + Clone + 'static,
|
||||
|
|
|
@ -249,6 +249,8 @@ pub mod context {
|
|||
pub use leptos_server as server;
|
||||
/// HTML element types.
|
||||
pub use tachys::html::element as html;
|
||||
/// HTML attribute types.
|
||||
pub use tachys::html::attribute as attr;
|
||||
/// HTML event types.
|
||||
#[doc(no_inline)]
|
||||
pub use tachys::html::event as ev;
|
||||
|
|
|
@ -17,15 +17,18 @@ use std::{
|
|||
cell::RefCell,
|
||||
fmt::Debug,
|
||||
future::{ready, Future, Ready},
|
||||
pin::Pin,
|
||||
rc::Rc,
|
||||
};
|
||||
use tachys::{
|
||||
either::Either,
|
||||
html::attribute::Attribute,
|
||||
hydration::Cursor,
|
||||
reactive_graph::RenderEffectState,
|
||||
renderer::{dom::Dom, Renderer},
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
add_attr::AddAnyAttr,
|
||||
any_view::AnyView,
|
||||
either::{EitherKeepAlive, EitherKeepAliveState},
|
||||
iterators::OptionState,
|
||||
|
@ -67,8 +70,8 @@ pub(crate) struct SuspenseBoundary<const TRANSITION: bool, Fal, Chil> {
|
|||
impl<const TRANSITION: bool, Fal, Chil, Rndr> Render<Rndr>
|
||||
for SuspenseBoundary<TRANSITION, Fal, Chil>
|
||||
where
|
||||
Fal: Render<Rndr> + 'static,
|
||||
Chil: Render<Rndr> + 'static,
|
||||
Fal: Render<Rndr> + Send + 'static,
|
||||
Chil: Render<Rndr> + Send + 'static,
|
||||
Rndr: Renderer + 'static,
|
||||
{
|
||||
type State =
|
||||
|
@ -100,6 +103,40 @@ where
|
|||
fn rebuild(self, _state: &mut Self::State) {}
|
||||
}
|
||||
|
||||
impl<const TRANSITION: bool, Fal, Chil, Rndr> AddAnyAttr<Rndr>
|
||||
for SuspenseBoundary<TRANSITION, Fal, Chil>
|
||||
where
|
||||
Fal: RenderHtml<Rndr> + Send + 'static,
|
||||
Chil: RenderHtml<Rndr> + Send + 'static,
|
||||
Rndr: Renderer + 'static,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> = SuspenseBoundary<
|
||||
TRANSITION,
|
||||
Fal,
|
||||
Chil::Output<SomeNewAttr::CloneableOwned>,
|
||||
>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
let attr = attr.into_cloneable_owned();
|
||||
let SuspenseBoundary {
|
||||
none_pending,
|
||||
fallback,
|
||||
children,
|
||||
} = self;
|
||||
SuspenseBoundary {
|
||||
none_pending,
|
||||
fallback,
|
||||
children: children.add_any_attr(attr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const TRANSITION: bool, Fal, Chil, Rndr> RenderHtml<Rndr>
|
||||
for SuspenseBoundary<TRANSITION, Fal, Chil>
|
||||
where
|
||||
|
@ -341,6 +378,39 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<Fut, Rndr> AddAnyAttr<Rndr> for Suspend<Fut>
|
||||
where
|
||||
Fut: Future + Send + 'static,
|
||||
Fut::Output: AddAnyAttr<Rndr>,
|
||||
Rndr: Renderer + 'static,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> = Suspend<
|
||||
Pin<
|
||||
Box<
|
||||
dyn Future<
|
||||
Output = <Fut::Output as AddAnyAttr<Rndr>>::Output<
|
||||
SomeNewAttr::CloneableOwned,
|
||||
>,
|
||||
> + Send,
|
||||
>,
|
||||
>,
|
||||
>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
let attr = attr.into_cloneable_owned();
|
||||
Suspend(Box::pin(async move {
|
||||
let this = self.0.await;
|
||||
this.add_any_attr(attr)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Fut, Rndr> RenderHtml<Rndr> for Suspend<Fut>
|
||||
where
|
||||
Fut: Future + Send + 'static,
|
||||
|
|
|
@ -102,6 +102,37 @@ pub(crate) fn component_to_tokens(
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let spreads = node.attributes().iter().filter_map(|attr| {
|
||||
use rstml::node::NodeBlock;
|
||||
use syn::{Expr, ExprRange, RangeLimits, Stmt};
|
||||
|
||||
if let NodeAttribute::Block(block) = attr {
|
||||
let dotted = if let NodeBlock::ValidBlock(block) = block {
|
||||
match block.stmts.first() {
|
||||
Some(Stmt::Expr(
|
||||
Expr::Range(ExprRange {
|
||||
start: None,
|
||||
limits: RangeLimits::HalfOpen(_),
|
||||
end: Some(end),
|
||||
..
|
||||
}),
|
||||
_,
|
||||
)) => Some(quote! { .add_any_attr(#end) }),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Some(dotted.unwrap_or_else(|| {
|
||||
quote! {
|
||||
.add_any_attr(#[allow(unused_braces)] { #node })
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
/*let directives = attrs
|
||||
.clone()
|
||||
.filter_map(|attr| {
|
||||
|
@ -244,6 +275,7 @@ pub(crate) fn component_to_tokens(
|
|||
#name_ref,
|
||||
props
|
||||
)
|
||||
#(#spreads)*
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -6,9 +6,13 @@ use leptos_hot_reload::parsing::is_component_node;
|
|||
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
|
||||
use proc_macro_error::abort;
|
||||
use quote::{quote, quote_spanned, ToTokens};
|
||||
use rstml::node::{KeyedAttribute, Node, NodeAttribute, NodeElement, NodeName};
|
||||
use rstml::node::{
|
||||
KeyedAttribute, Node, NodeAttribute, NodeBlock, NodeElement, NodeName,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use syn::{spanned::Spanned, Expr, ExprPath, Lit, LitStr};
|
||||
use syn::{
|
||||
spanned::Spanned, Expr, ExprPath, ExprRange, Lit, LitStr, RangeLimits, Stmt,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum TagType {
|
||||
|
@ -300,7 +304,29 @@ fn attribute_to_tokens(
|
|||
global_class: Option<&TokenTree>,
|
||||
) -> TokenStream {
|
||||
match node {
|
||||
NodeAttribute::Block(_) => todo!(),
|
||||
NodeAttribute::Block(node) => {
|
||||
let dotted = if let NodeBlock::ValidBlock(block) = node {
|
||||
match block.stmts.first() {
|
||||
Some(Stmt::Expr(
|
||||
Expr::Range(ExprRange {
|
||||
start: None,
|
||||
limits: RangeLimits::HalfOpen(_),
|
||||
end: Some(end),
|
||||
..
|
||||
}),
|
||||
_,
|
||||
)) => Some(quote! { .add_any_attr(#end) }),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
dotted.unwrap_or_else(|| {
|
||||
quote! {
|
||||
.add_any_attr(#[allow(unused_braces)] { #node })
|
||||
}
|
||||
})
|
||||
}
|
||||
NodeAttribute::Attribute(node) => {
|
||||
let name = node.key.to_string();
|
||||
if name == "node_ref" {
|
||||
|
|
|
@ -17,7 +17,7 @@ pub mod prelude {
|
|||
node_ref::NodeRefAttribute,
|
||||
},
|
||||
renderer::{dom::Dom, Renderer},
|
||||
view::{Mountable, Render, RenderHtml},
|
||||
view::{add_attr::AddAnyAttr, Mountable, Render, RenderHtml},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ where
|
|||
{
|
||||
type State = (R::Element, Oco<'static, str>);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.as_str().len()
|
||||
|
@ -151,6 +152,12 @@ where
|
|||
self.upgrade_inplace();
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(mut self) -> Self::CloneableOwned {
|
||||
// ensure it's reference-counted
|
||||
self.upgrade_inplace();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoClass<R> for Oco<'static, str>
|
||||
|
@ -159,6 +166,7 @@ where
|
|||
{
|
||||
type State = (R::Element, Self);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.as_str().len()
|
||||
|
@ -193,4 +201,10 @@ where
|
|||
self.upgrade_inplace();
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(mut self) -> Self::CloneableOwned {
|
||||
// ensure it's reference-counted
|
||||
self.upgrade_inplace();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -376,6 +376,8 @@ mod stable {
|
|||
R: DomRenderer,
|
||||
{
|
||||
type State = RenderEffectState<C::State>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -400,6 +402,14 @@ mod stable {
|
|||
fn rebuild(self, _state: &mut Self::State) {
|
||||
// TODO rebuild here?
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoClass<R> for (&'static str, $sig<bool>)
|
||||
|
@ -407,6 +417,8 @@ mod stable {
|
|||
R: DomRenderer,
|
||||
{
|
||||
type State = RenderEffectState<(R::ClassList, bool)>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.0.len()
|
||||
|
@ -437,6 +449,14 @@ mod stable {
|
|||
fn rebuild(self, _state: &mut Self::State) {
|
||||
// TODO rebuild here?
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -450,6 +470,8 @@ mod stable {
|
|||
R: DomRenderer,
|
||||
{
|
||||
type State = RenderEffectState<C::State>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -474,6 +496,14 @@ mod stable {
|
|||
fn rebuild(self, _state: &mut Self::State) {
|
||||
// TODO rebuild here?
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoClass<R> for (&'static str, $sig<bool>)
|
||||
|
@ -481,6 +511,8 @@ mod stable {
|
|||
R: DomRenderer,
|
||||
{
|
||||
type State = RenderEffectState<(R::ClassList, bool)>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.0.len()
|
||||
|
@ -511,6 +543,14 @@ mod stable {
|
|||
fn rebuild(self, _state: &mut Self::State) {
|
||||
// TODO rebuild here?
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -90,6 +90,8 @@ mod stable {
|
|||
R: DomRenderer,
|
||||
{
|
||||
type State = RenderEffect<V::State>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -114,6 +116,14 @@ mod stable {
|
|||
}
|
||||
|
||||
fn rebuild(self, _state: &mut Self::State) {}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -127,6 +137,8 @@ mod stable {
|
|||
R: DomRenderer,
|
||||
{
|
||||
type State = RenderEffect<V::State>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -151,6 +163,14 @@ mod stable {
|
|||
}
|
||||
|
||||
fn rebuild(self, _state: &mut Self::State) {}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ where
|
|||
impl<F, V, R> RenderHtml<R> for F
|
||||
where
|
||||
F: ReactiveFunction<Output = V>,
|
||||
V: RenderHtml<R>,
|
||||
V: RenderHtml<R> + 'static,
|
||||
V::State: 'static,
|
||||
|
||||
R: Renderer + 'static,
|
||||
|
@ -203,22 +203,21 @@ where
|
|||
impl<F, V, R> AddAnyAttr<R> for F
|
||||
where
|
||||
F: ReactiveFunction<Output = V>,
|
||||
V: AddAnyAttr<R>,
|
||||
V: RenderHtml<R> + 'static,
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> =
|
||||
SharedReactiveFunction<V::Output<SomeNewAttr>>;
|
||||
Box<dyn FnMut() -> V::Output<SomeNewAttr::CloneableOwned> + Send>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
self,
|
||||
mut self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
/*let attr = attr.into_cloneable_owned();
|
||||
Arc::new(Mutex::new(move || self.invoke().add_any_attr(attr.clone())));*/
|
||||
todo!()
|
||||
let attr = attr.into_cloneable_owned();
|
||||
Box::new(move || self.invoke().add_any_attr(attr.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,11 +404,13 @@ where
|
|||
mod stable {
|
||||
use super::RenderEffectState;
|
||||
use crate::{
|
||||
html::attribute::AttributeValue,
|
||||
html::attribute::{Attribute, AttributeValue},
|
||||
hydration::Cursor,
|
||||
renderer::Renderer,
|
||||
ssr::StreamBuilder,
|
||||
view::{Position, PositionState, Render, RenderHtml},
|
||||
view::{
|
||||
add_attr::AddAnyAttr, Position, PositionState, Render, RenderHtml,
|
||||
},
|
||||
};
|
||||
use reactive_graph::{
|
||||
computed::{ArcMemo, Memo},
|
||||
|
@ -440,6 +441,25 @@ mod stable {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V, R> AddAnyAttr<R> for $sig<V>
|
||||
where
|
||||
V: RenderHtml<R> + Clone + Send + Sync + 'static,
|
||||
V::State: 'static,
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> = $sig<V>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
mut self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, R> RenderHtml<R> for $sig<V>
|
||||
where
|
||||
V: RenderHtml<R> + Clone + Send + Sync + 'static,
|
||||
|
@ -496,6 +516,8 @@ mod stable {
|
|||
R: Renderer,
|
||||
{
|
||||
type State = RenderEffectState<V::State>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -527,6 +549,14 @@ mod stable {
|
|||
fn rebuild(self, _key: &str, _state: &mut Self::State) {
|
||||
// TODO rebuild
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -535,7 +565,7 @@ mod stable {
|
|||
($sig:ident) => {
|
||||
impl<V, R> Render<R> for $sig<V>
|
||||
where
|
||||
V: Render<R> + Clone + 'static,
|
||||
V: Render<R> + Send + Sync + Clone + 'static,
|
||||
V::State: 'static,
|
||||
|
||||
R: Renderer,
|
||||
|
@ -553,6 +583,25 @@ mod stable {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V, R> AddAnyAttr<R> for $sig<V>
|
||||
where
|
||||
V: RenderHtml<R> + Clone + Send + Sync + 'static,
|
||||
V::State: 'static,
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> = $sig<V>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
mut self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, R> RenderHtml<R> for $sig<V>
|
||||
where
|
||||
V: RenderHtml<R> + Clone + Send + Sync + 'static,
|
||||
|
@ -609,6 +658,8 @@ mod stable {
|
|||
R: Renderer,
|
||||
{
|
||||
type State = RenderEffectState<V::State>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -640,6 +691,14 @@ mod stable {
|
|||
fn rebuild(self, _key: &str, _state: &mut Self::State) {
|
||||
// TODO rebuild
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -93,6 +93,8 @@ mod stable {
|
|||
R: DomRenderer,
|
||||
{
|
||||
type State = RenderEffect<V::State>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
|
@ -113,6 +115,14 @@ mod stable {
|
|||
fn rebuild(self, _state: &mut Self::State, _key: &str) {
|
||||
// TODO rebuild
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -121,11 +131,13 @@ mod stable {
|
|||
($sig:ident) => {
|
||||
impl<V, R> IntoProperty<R> for $sig<V>
|
||||
where
|
||||
V: IntoProperty<R> + Clone + 'static,
|
||||
V: IntoProperty<R> + Send + Sync + Clone + 'static,
|
||||
V::State: 'static,
|
||||
R: DomRenderer,
|
||||
{
|
||||
type State = RenderEffect<V::State>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
|
@ -146,6 +158,14 @@ mod stable {
|
|||
fn rebuild(self, _state: &mut Self::State, _key: &str) {
|
||||
// TODO rebuild
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,12 +20,6 @@ pub mod tuples;
|
|||
///
|
||||
/// It is generic over the renderer itself, as long as that implements the [`Renderer`]
|
||||
/// trait.
|
||||
#[diagnostic::on_unimplemented(
|
||||
message = "`Render<{R}>` is not implemented for `{Self}`",
|
||||
label = "My Label",
|
||||
note = "Note 1",
|
||||
note = "Note 2"
|
||||
)]
|
||||
pub trait Render<R: Renderer>: Sized {
|
||||
/// The “view state” for this type, which can be retained between updates.
|
||||
///
|
||||
|
|
Loading…
Reference in a new issue