mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
stashing
This commit is contained in:
parent
45fd9423f8
commit
3c13280bf6
40 changed files with 1282 additions and 178 deletions
|
@ -76,8 +76,7 @@ impl<T: IntoView> RenderHtml<Dom> for View<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl<T: AddAnyAttr<Dom>> AddAnyAttr<Dom> for View<T> {
|
||||
impl<T: IntoView> AddAnyAttr<Dom> for View<T> {
|
||||
type Output<SomeNewAttr: Attribute<Dom>> =
|
||||
<T as AddAnyAttr<Dom>>::Output<SomeNewAttr>;
|
||||
|
||||
|
@ -90,14 +89,4 @@ impl<T: AddAnyAttr<Dom>> AddAnyAttr<Dom> for View<T> {
|
|||
{
|
||||
self.0.add_any_attr(attr)
|
||||
}
|
||||
|
||||
fn add_any_attr_by_ref<NewAttr: Attribute<Dom>>(
|
||||
self,
|
||||
attr: &NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Dom>,
|
||||
{
|
||||
self.0.add_any_attr_by_ref(attr)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ impl ToAnySubscriber for Arc<RwLock<EffectInner>> {
|
|||
impl ReactiveNode for RwLock<EffectInner> {
|
||||
fn mark_subscribers_check(&self) {}
|
||||
|
||||
// TODO check if this actually works for memos
|
||||
fn update_if_necessary(&self) -> bool {
|
||||
let sources = {
|
||||
let guard = self.read().or_poisoned();
|
||||
|
|
|
@ -3,6 +3,7 @@ use core::{fmt::Debug, hash::Hash};
|
|||
use std::{cell::RefCell, mem, sync::Weak};
|
||||
|
||||
thread_local! {
|
||||
// TODO this can be a Cell
|
||||
static OBSERVER: RefCell<Option<AnySubscriber>> = const { RefCell::new(None) };
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,18 @@ impl<T, Inner> ReadGuard<T, Inner> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, Inner> Clone for ReadGuard<T, Inner>
|
||||
where
|
||||
Inner: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
ty: self.ty,
|
||||
inner: self.inner.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Inner> Deref for ReadGuard<T, Inner>
|
||||
where
|
||||
Inner: Deref<Target = T>,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::{
|
||||
html::attribute::Attribute,
|
||||
hydration::Cursor,
|
||||
renderer::Renderer,
|
||||
ssr::StreamBuilder,
|
||||
view::{
|
||||
either::EitherState, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
add_attr::AddAnyAttr, either::EitherState, Mountable, Position,
|
||||
PositionState, Render, RenderHtml,
|
||||
},
|
||||
};
|
||||
use any_spawner::Executor;
|
||||
|
@ -146,6 +147,27 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<const TRANSITION: bool, Fal, Fut, Rndr> AddAnyAttr<Rndr>
|
||||
for Suspend<TRANSITION, Fal, Fut>
|
||||
where
|
||||
Fal: RenderHtml<Rndr> + 'static,
|
||||
Fut: Future + Send + 'static,
|
||||
Fut::Output: RenderHtml<Rndr> + Send,
|
||||
Rndr: Renderer + 'static,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> = Self;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
_attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const TRANSITION: bool, Fal, Fut, Rndr> RenderHtml<Rndr>
|
||||
for Suspend<TRANSITION, Fal, Fut>
|
||||
where
|
||||
|
|
|
@ -162,6 +162,7 @@ where
|
|||
|
||||
type State = AnyAttributeState<R>;
|
||||
type Cloneable = ();
|
||||
type CloneableOwned = ();
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.html_len
|
||||
|
@ -199,4 +200,8 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CustomAttr<K, V, R>
|
||||
where
|
||||
K: CustomAttributeKey,
|
||||
|
@ -31,6 +32,21 @@ where
|
|||
rndr: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<K, V, R> Clone for CustomAttr<K, V, R>
|
||||
where
|
||||
K: CustomAttributeKey,
|
||||
V: AttributeValue<R> + Clone,
|
||||
R: DomRenderer,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
key: self.key.clone(),
|
||||
value: self.value.clone(),
|
||||
rndr: self.rndr.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, R> Attribute<R> for CustomAttr<K, V, R>
|
||||
where
|
||||
K: CustomAttributeKey,
|
||||
|
@ -40,6 +56,7 @@ where
|
|||
const MIN_LENGTH: usize = 0;
|
||||
type State = V::State;
|
||||
type Cloneable = CustomAttr<K, V::Cloneable, R>;
|
||||
type CloneableOwned = CustomAttr<K, V::CloneableOwned, R>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.key.as_ref().len() + 3 + self.value.html_len()
|
||||
|
@ -78,6 +95,14 @@ where
|
|||
rndr: self.rndr,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
CustomAttr {
|
||||
key: self.key,
|
||||
value: self.value.into_cloneable_owned(),
|
||||
rndr: self.rndr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, R> NextAttribute<R> for CustomAttr<K, V, R>
|
||||
|
@ -115,19 +140,16 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub trait CustomAttributeKey: AsRef<str> + Send {
|
||||
// TODO this needs to be a method, not a const
|
||||
pub trait CustomAttributeKey: Clone + AsRef<str> + Send + 'static {
|
||||
const KEY: &'static str;
|
||||
}
|
||||
|
||||
impl<'a> CustomAttributeKey for &'a str {
|
||||
impl CustomAttributeKey for &'static str {
|
||||
const KEY: &'static str = "";
|
||||
}
|
||||
|
||||
impl<'a> CustomAttributeKey for Cow<'a, str> {
|
||||
const KEY: &'static str = "";
|
||||
}
|
||||
|
||||
impl CustomAttributeKey for &String {
|
||||
impl CustomAttributeKey for Cow<'static, str> {
|
||||
const KEY: &'static str = "";
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use super::{Attr, AttributeValue};
|
|||
use crate::renderer::Renderer;
|
||||
use std::{fmt::Debug, marker::PhantomData};
|
||||
|
||||
pub trait AttributeKey: Send {
|
||||
pub trait AttributeKey: Clone + Send + 'static {
|
||||
const KEY: &'static str;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,8 @@ pub trait Attribute<R: Renderer>: NextAttribute<R> + Send {
|
|||
const MIN_LENGTH: usize;
|
||||
|
||||
type State;
|
||||
type Cloneable;
|
||||
type Cloneable: Attribute<R> + Clone;
|
||||
type CloneableOwned: Attribute<R> + Clone + 'static;
|
||||
|
||||
fn html_len(&self) -> usize;
|
||||
|
||||
|
@ -35,6 +36,8 @@ pub trait Attribute<R: Renderer>: NextAttribute<R> + Send {
|
|||
fn rebuild(self, state: &mut Self::State);
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable;
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned;
|
||||
}
|
||||
|
||||
pub trait NextAttribute<R: Renderer> {
|
||||
|
@ -54,6 +57,7 @@ where
|
|||
|
||||
type State = ();
|
||||
type Cloneable = ();
|
||||
type CloneableOwned = ();
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -78,6 +82,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> NextAttribute<R> for ()
|
||||
|
@ -101,6 +109,17 @@ where
|
|||
V: AttributeValue<R>,
|
||||
R: Renderer;
|
||||
|
||||
impl<K, V, R> Clone for Attr<K, V, R>
|
||||
where
|
||||
K: AttributeKey,
|
||||
V: AttributeValue<R> + Clone,
|
||||
R: Renderer,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone(), self.1.clone(), PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, R> ToTemplate for Attr<K, V, R>
|
||||
where
|
||||
K: AttributeKey,
|
||||
|
@ -128,6 +147,7 @@ where
|
|||
|
||||
type State = V::State;
|
||||
type Cloneable = Attr<K, V::Cloneable, R>;
|
||||
type CloneableOwned = Attr<K, V::CloneableOwned, R>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
K::KEY.len() + 3 + self.1.html_len()
|
||||
|
@ -158,6 +178,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
Attr(self.0, self.1.into_cloneable(), PhantomData)
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
Attr(self.0, self.1.into_cloneable_owned(), PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, R> NextAttribute<R> for Attr<K, V, R>
|
||||
|
@ -188,6 +212,7 @@ macro_rules! impl_attr_for_tuples {
|
|||
|
||||
type State = ($first::State, $($ty::State,)*);
|
||||
type Cloneable = ($first::Cloneable, $($ty::Cloneable,)*);
|
||||
type CloneableOwned = ($first::CloneableOwned, $($ty::CloneableOwned,)*);
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
#[allow(non_snake_case)]
|
||||
|
@ -239,6 +264,14 @@ macro_rules! impl_attr_for_tuples {
|
|||
$($ty.into_cloneable()),*
|
||||
)
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
let ($first, $($ty,)*) = self;
|
||||
(
|
||||
$first.into_cloneable_owned(),
|
||||
$($ty.into_cloneable_owned()),*
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<$first, $($ty),*, Rndr> NextAttribute<Rndr> for ($first, $($ty,)*)
|
||||
|
@ -273,6 +306,7 @@ macro_rules! impl_attr_for_tuples_truncate_additional {
|
|||
|
||||
type State = ($first::State, $($ty::State,)*);
|
||||
type Cloneable = ($first::Cloneable, $($ty::Cloneable,)*);
|
||||
type CloneableOwned = ($first::CloneableOwned, $($ty::CloneableOwned,)*);
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
#[allow(non_snake_case)]
|
||||
|
@ -324,6 +358,14 @@ macro_rules! impl_attr_for_tuples_truncate_additional {
|
|||
$($ty.into_cloneable()),*
|
||||
)
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
let ($first, $($ty,)*) = self;
|
||||
(
|
||||
$first.into_cloneable_owned(),
|
||||
$($ty.into_cloneable_owned()),*
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<$first, $($ty),*, Rndr> NextAttribute<Rndr> for ($first, $($ty,)*)
|
||||
|
@ -354,6 +396,7 @@ where
|
|||
|
||||
type State = A::State;
|
||||
type Cloneable = (A::Cloneable,);
|
||||
type CloneableOwned = (A::CloneableOwned,);
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.0.html_len()
|
||||
|
@ -387,6 +430,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
(self.0.into_cloneable(),)
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
(self.0.into_cloneable_owned(),)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, Rndr> NextAttribute<Rndr> for (A,)
|
||||
|
|
|
@ -21,6 +21,11 @@ pub trait AttributeValue<R: Renderer>: Send {
|
|||
/// `Arc<str>`, as two different clones of a `String` will still have the same value.
|
||||
type Cloneable: AttributeValue<R> + Clone;
|
||||
|
||||
/// A cloneable type that is also `'static`. This is used for spreading across types when the
|
||||
/// spreadable attribute needs to be owned. In some cases (`&'a str` to `Arc<str>`, etc.) the owned
|
||||
/// cloneable type has worse performance than the cloneable type, so they are separate.
|
||||
type CloneableOwned: AttributeValue<R> + Clone + 'static;
|
||||
|
||||
fn html_len(&self) -> usize;
|
||||
|
||||
fn to_html(self, key: &str, buf: &mut String);
|
||||
|
@ -38,6 +43,8 @@ pub trait AttributeValue<R: Renderer>: Send {
|
|||
fn rebuild(self, key: &str, state: &mut Self::State);
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable;
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned;
|
||||
}
|
||||
|
||||
impl<R> AttributeValue<R> for ()
|
||||
|
@ -46,6 +53,7 @@ where
|
|||
{
|
||||
type State = ();
|
||||
type Cloneable = ();
|
||||
type CloneableOwned = ();
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -64,6 +72,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R> AttributeValue<R> for &'a str
|
||||
|
@ -71,7 +83,8 @@ where
|
|||
R: Renderer,
|
||||
{
|
||||
type State = (R::Element, &'a str);
|
||||
type Cloneable = Self;
|
||||
type Cloneable = &'a str;
|
||||
type CloneableOwned = Arc<str>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
|
@ -116,6 +129,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
|
@ -126,6 +143,7 @@ where
|
|||
{
|
||||
type State = ();
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
V.len()
|
||||
|
@ -159,6 +177,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R> AttributeValue<R> for &'a String
|
||||
|
@ -167,6 +189,7 @@ where
|
|||
{
|
||||
type State = (R::Element, &'a String);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Arc<str>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
|
@ -207,6 +230,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.as_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> AttributeValue<R> for String
|
||||
|
@ -215,6 +242,7 @@ where
|
|||
{
|
||||
type State = (R::Element, String);
|
||||
type Cloneable = Arc<str>;
|
||||
type CloneableOwned = Arc<str>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
|
@ -255,6 +283,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.into()
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> AttributeValue<R> for Arc<str>
|
||||
|
@ -263,6 +295,7 @@ where
|
|||
{
|
||||
type State = (R::Element, Arc<str>);
|
||||
type Cloneable = Arc<str>;
|
||||
type CloneableOwned = Arc<str>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
|
@ -303,6 +336,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
// TODO impl AttributeValue for Rc<str> and Arc<str> too
|
||||
|
||||
|
@ -312,6 +349,7 @@ where
|
|||
{
|
||||
type State = (R::Element, bool);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -361,6 +399,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, R> AttributeValue<R> for Option<V>
|
||||
|
@ -370,6 +412,7 @@ where
|
|||
{
|
||||
type State = (R::Element, Option<V::State>);
|
||||
type Cloneable = Option<V::Cloneable>;
|
||||
type CloneableOwned = Option<V::CloneableOwned>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
match self {
|
||||
|
@ -427,6 +470,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.map(|value| value.into_cloneable())
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.map(|value| value.into_cloneable_owned())
|
||||
}
|
||||
}
|
||||
|
||||
fn escape_attr(value: &str) -> Cow<'_, str> {
|
||||
|
@ -442,6 +489,7 @@ macro_rules! render_primitive {
|
|||
{
|
||||
type State = (R::Element, $child_type);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -482,6 +530,10 @@ macro_rules! render_primitive {
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
|
|
@ -17,15 +17,24 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Class<C, R>
|
||||
where
|
||||
C: IntoClass<R>,
|
||||
R: DomRenderer,
|
||||
{
|
||||
#[derive(Debug)]
|
||||
pub struct Class<C, R> {
|
||||
class: C,
|
||||
rndr: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<C, R> Clone for Class<C, R>
|
||||
where
|
||||
C: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
class: self.class.clone(),
|
||||
rndr: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, R> Attribute<R> for Class<C, R>
|
||||
where
|
||||
C: IntoClass<R>,
|
||||
|
@ -35,6 +44,7 @@ where
|
|||
|
||||
type State = C::State;
|
||||
type Cloneable = Class<C::Cloneable, R>;
|
||||
type CloneableOwned = Class<C::CloneableOwned, R>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.class.html_len() + 1
|
||||
|
@ -69,6 +79,13 @@ where
|
|||
rndr: self.rndr,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
Class {
|
||||
class: self.class.into_cloneable_owned(),
|
||||
rndr: self.rndr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, R> NextAttribute<R> for Class<C, R>
|
||||
|
@ -110,6 +127,7 @@ pub trait IntoClass<R: DomRenderer>: Send {
|
|||
|
||||
type State;
|
||||
type Cloneable: IntoClass<R> + Clone;
|
||||
type CloneableOwned: IntoClass<R> + Clone + 'static;
|
||||
|
||||
fn html_len(&self) -> usize;
|
||||
|
||||
|
@ -125,6 +143,8 @@ pub trait IntoClass<R: DomRenderer>: Send {
|
|||
fn rebuild(self, state: &mut Self::State);
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable;
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned;
|
||||
}
|
||||
|
||||
impl<'a, R> IntoClass<R> for &'a str
|
||||
|
@ -133,6 +153,7 @@ where
|
|||
{
|
||||
type State = (R::Element, Self);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Arc<str>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
|
@ -165,6 +186,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoClass<R> for String
|
||||
|
@ -173,6 +198,7 @@ where
|
|||
{
|
||||
type State = (R::Element, Self);
|
||||
type Cloneable = Arc<str>;
|
||||
type CloneableOwned = Arc<str>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
|
@ -205,6 +231,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.into()
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoClass<R> for Arc<str>
|
||||
|
@ -213,6 +243,7 @@ where
|
|||
{
|
||||
type State = (R::Element, Self);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
|
@ -245,6 +276,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoClass<R> for (&'static str, bool)
|
||||
|
@ -253,6 +288,7 @@ where
|
|||
{
|
||||
type State = (R::ClassList, bool);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.0.len()
|
||||
|
@ -299,6 +335,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
|
@ -311,6 +351,7 @@ where
|
|||
|
||||
type State = ();
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
V.len()
|
||||
|
@ -336,6 +377,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/* #[cfg(test)]
|
||||
|
|
|
@ -18,16 +18,24 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct InnerHtml<T, R>
|
||||
where
|
||||
T: InnerHtmlValue<R>,
|
||||
R: DomRenderer,
|
||||
{
|
||||
#[derive(Debug)]
|
||||
pub struct InnerHtml<T, R> {
|
||||
value: T,
|
||||
rndr: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<T, R> Clone for InnerHtml<T, R>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
value: self.value.clone(),
|
||||
rndr: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R> Attribute<R> for InnerHtml<T, R>
|
||||
where
|
||||
T: InnerHtmlValue<R>,
|
||||
|
@ -37,6 +45,7 @@ where
|
|||
|
||||
type State = T::State;
|
||||
type Cloneable = InnerHtml<T::Cloneable, R>;
|
||||
type CloneableOwned = InnerHtml<T::CloneableOwned, R>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.value.html_len()
|
||||
|
@ -73,6 +82,13 @@ where
|
|||
rndr: self.rndr,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
InnerHtml {
|
||||
value: self.value.into_cloneable_owned(),
|
||||
rndr: self.rndr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R> NextAttribute<R> for InnerHtml<T, R>
|
||||
|
@ -124,6 +140,7 @@ where
|
|||
pub trait InnerHtmlValue<R: DomRenderer>: Send {
|
||||
type State;
|
||||
type Cloneable: InnerHtmlValue<R> + Clone;
|
||||
type CloneableOwned: InnerHtmlValue<R> + Clone + 'static;
|
||||
|
||||
fn html_len(&self) -> usize;
|
||||
|
||||
|
@ -138,6 +155,8 @@ pub trait InnerHtmlValue<R: DomRenderer>: Send {
|
|||
fn rebuild(self, state: &mut Self::State);
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable;
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned;
|
||||
}
|
||||
|
||||
impl<R> InnerHtmlValue<R> for String
|
||||
|
@ -146,6 +165,7 @@ where
|
|||
{
|
||||
type State = (R::Element, Self);
|
||||
type Cloneable = Arc<str>;
|
||||
type CloneableOwned = Arc<str>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
|
@ -182,6 +202,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.into()
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::Cloneable {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> InnerHtmlValue<R> for Arc<str>
|
||||
|
@ -190,6 +214,7 @@ where
|
|||
{
|
||||
type State = (R::Element, Self);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
|
@ -226,6 +251,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R> InnerHtmlValue<R> for &'a str
|
||||
|
@ -234,6 +263,7 @@ where
|
|||
{
|
||||
type State = (R::Element, Self);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Arc<str>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
|
@ -270,6 +300,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R> InnerHtmlValue<R> for Option<T>
|
||||
|
@ -279,6 +313,7 @@ where
|
|||
{
|
||||
type State = Option<T::State>;
|
||||
type Cloneable = Option<T::Cloneable>;
|
||||
type CloneableOwned = Option<T::CloneableOwned>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
match self {
|
||||
|
@ -313,4 +348,8 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.map(|inner| inner.into_cloneable())
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.map(|inner| inner.into_cloneable_owned())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,13 +121,6 @@ where
|
|||
rndr,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_any_attr_by_ref<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: &NewAttr,
|
||||
) -> Self::Output<NewAttr> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ElementChild<Rndr, NewChild>
|
||||
|
|
|
@ -3,7 +3,6 @@ use crate::{
|
|||
renderer::{CastFrom, DomRenderer, RemoveEventHandler},
|
||||
view::{Position, ToTemplate},
|
||||
};
|
||||
use or_poisoned::OrPoisoned;
|
||||
use send_wrapper::SendWrapper;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
|
@ -12,10 +11,41 @@ use std::{
|
|||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
rc::Rc,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use wasm_bindgen::convert::FromWasmAbi;
|
||||
|
||||
pub type SharedEventCallback<E> = Rc<RefCell<dyn FnMut(E)>>;
|
||||
|
||||
pub trait EventCallback<E>: 'static {
|
||||
fn invoke(&mut self, event: E);
|
||||
|
||||
fn into_shared(self) -> SharedEventCallback<E>;
|
||||
}
|
||||
|
||||
impl<E: 'static> EventCallback<E> for SharedEventCallback<E> {
|
||||
fn invoke(&mut self, event: E) {
|
||||
let mut fun = self.borrow_mut();
|
||||
fun(event)
|
||||
}
|
||||
|
||||
fn into_shared(self) -> SharedEventCallback<E> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, E> EventCallback<E> for F
|
||||
where
|
||||
F: FnMut(E) + 'static,
|
||||
{
|
||||
fn invoke(&mut self, event: E) {
|
||||
self(event)
|
||||
}
|
||||
|
||||
fn into_shared(self) -> SharedEventCallback<E> {
|
||||
Rc::new(RefCell::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Targeted<E, T, R> {
|
||||
event: E,
|
||||
el_ty: PhantomData<T>,
|
||||
|
@ -94,16 +124,29 @@ where
|
|||
on(event, Box::new(move |ev: E::EventType| cb(ev.into())))
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct On<E, F, R> {
|
||||
event: E,
|
||||
cb: SendWrapper<F>,
|
||||
ty: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<E, F, R> Clone for On<E, F, R>
|
||||
where
|
||||
E: Clone,
|
||||
F: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
event: self.event.clone(),
|
||||
cb: self.cb.clone(),
|
||||
ty: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, F, R> On<E, F, R>
|
||||
where
|
||||
F: FnMut(E::EventType) + 'static,
|
||||
F: EventCallback<E::EventType>,
|
||||
E: EventDescriptor + Send + 'static,
|
||||
E::EventType: 'static,
|
||||
R: DomRenderer,
|
||||
|
@ -125,7 +168,7 @@ where
|
|||
let mut cb = self.cb.take();
|
||||
let cb = Box::new(move |ev: R::Event| {
|
||||
let ev = E::EventType::from(ev);
|
||||
cb(ev);
|
||||
cb.invoke(ev);
|
||||
}) as Box<dyn FnMut(R::Event)>;
|
||||
|
||||
attach_inner::<R>(
|
||||
|
@ -150,7 +193,7 @@ where
|
|||
|
||||
impl<E, F, R> Attribute<R> for On<E, F, R>
|
||||
where
|
||||
F: FnMut(E::EventType) + 'static,
|
||||
F: EventCallback<E::EventType>,
|
||||
E: EventDescriptor + Send + 'static,
|
||||
E::EventType: 'static,
|
||||
R: DomRenderer,
|
||||
|
@ -159,7 +202,8 @@ where
|
|||
const MIN_LENGTH: usize = 0;
|
||||
// a function that can be called once to remove the event listener
|
||||
type State = (R::Element, Option<Box<dyn FnOnce(&R::Element)>>);
|
||||
type Cloneable = On<E, Arc<dyn FnMut(E::EventType)>, R>;
|
||||
type Cloneable = On<E, SharedEventCallback<E::EventType>, R>;
|
||||
type CloneableOwned = On<E, SharedEventCallback<E::EventType>, R>;
|
||||
|
||||
#[inline(always)]
|
||||
fn html_len(&self) -> usize {
|
||||
|
@ -198,12 +242,16 @@ where
|
|||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
let cb = Rc::new(RefCell::new(self.cb));
|
||||
On {
|
||||
cb: SendWrapper::new(Arc::new(move |ev| {
|
||||
let mut cb = cb.borrow_mut();
|
||||
cb(ev)
|
||||
})),
|
||||
cb: SendWrapper::new(self.cb.take().into_shared()),
|
||||
event: self.event,
|
||||
ty: self.ty,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
On {
|
||||
cb: SendWrapper::new(self.cb.take().into_shared()),
|
||||
event: self.event,
|
||||
ty: self.ty,
|
||||
}
|
||||
|
@ -212,7 +260,7 @@ where
|
|||
|
||||
impl<E, F, R> NextAttribute<R> for On<E, F, R>
|
||||
where
|
||||
F: FnMut(E::EventType) + 'static,
|
||||
F: EventCallback<E::EventType>,
|
||||
E: EventDescriptor + Send + 'static,
|
||||
E::EventType: 'static,
|
||||
R: DomRenderer,
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use super::attribute::Attribute;
|
||||
use crate::{
|
||||
hydration::Cursor,
|
||||
prelude::{Render, RenderHtml},
|
||||
renderer::Renderer,
|
||||
ssr::StreamBuilder,
|
||||
view::{Position, PositionState},
|
||||
view::{add_attr::AddAnyAttr, Position, PositionState},
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
@ -58,6 +59,34 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<Rndr, View> AddAnyAttr<Rndr> for Island<Rndr, View>
|
||||
where
|
||||
View: RenderHtml<Rndr>,
|
||||
Rndr: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> =
|
||||
Island<Rndr, <View as AddAnyAttr<Rndr>>::Output<SomeNewAttr>>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
let Island {
|
||||
component,
|
||||
view,
|
||||
rndr,
|
||||
} = self;
|
||||
Island {
|
||||
component,
|
||||
view: view.add_any_attr(attr),
|
||||
rndr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rndr, View> RenderHtml<Rndr> for Island<Rndr, View>
|
||||
where
|
||||
View: RenderHtml<Rndr>,
|
||||
|
@ -151,6 +180,29 @@ where
|
|||
fn rebuild(self, _state: &mut Self::State) {}
|
||||
}
|
||||
|
||||
impl<Rndr, View> AddAnyAttr<Rndr> for IslandChildren<Rndr, View>
|
||||
where
|
||||
View: RenderHtml<Rndr>,
|
||||
Rndr: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> =
|
||||
IslandChildren<Rndr, <View as AddAnyAttr<Rndr>>::Output<SomeNewAttr>>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
let IslandChildren { view, rndr } = self;
|
||||
IslandChildren {
|
||||
view: view.add_any_attr(attr),
|
||||
rndr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rndr, View> RenderHtml<Rndr> for IslandChildren<Rndr, View>
|
||||
where
|
||||
View: RenderHtml<Rndr>,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use self::attribute::Attribute;
|
||||
use crate::{
|
||||
no_attrs,
|
||||
renderer::Renderer,
|
||||
view::{Position, Render, RenderHtml},
|
||||
view::{add_attr::AddAnyAttr, Position, Render, RenderHtml},
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
@ -33,6 +35,8 @@ impl<R: Renderer> Render<R> for Doctype<R> {
|
|||
fn rebuild(self, _state: &mut Self::State) {}
|
||||
}
|
||||
|
||||
no_attrs!(Doctype<R>);
|
||||
|
||||
impl<R> RenderHtml<R> for Doctype<R>
|
||||
where
|
||||
R: Renderer + Send,
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub trait NodeRefContainer<E, Rndr>: Send
|
||||
pub trait NodeRefContainer<E, Rndr>: Send + Clone
|
||||
where
|
||||
E: ElementType,
|
||||
Rndr: Renderer,
|
||||
|
@ -16,17 +16,26 @@ where
|
|||
fn load(self, el: &Rndr::Element);
|
||||
}
|
||||
|
||||
pub struct NodeRefAttr<E, C, Rndr>
|
||||
where
|
||||
E: ElementType,
|
||||
C: NodeRefContainer<E, Rndr>,
|
||||
Rndr: Renderer,
|
||||
{
|
||||
#[derive(Debug)]
|
||||
pub struct NodeRefAttr<E, C, Rndr> {
|
||||
container: C,
|
||||
ty: PhantomData<E>,
|
||||
rndr: PhantomData<Rndr>,
|
||||
}
|
||||
|
||||
impl<E, C, Rndr> Clone for NodeRefAttr<E, C, Rndr>
|
||||
where
|
||||
C: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
container: self.container.clone(),
|
||||
ty: PhantomData,
|
||||
rndr: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn node_ref<E, C, Rndr>(container: C) -> NodeRefAttr<E, C, Rndr>
|
||||
where
|
||||
E: ElementType,
|
||||
|
@ -49,7 +58,8 @@ where
|
|||
{
|
||||
const MIN_LENGTH: usize = 0;
|
||||
type State = ();
|
||||
type Cloneable = Self;
|
||||
type Cloneable = ();
|
||||
type CloneableOwned = ();
|
||||
|
||||
#[inline(always)]
|
||||
fn html_len(&self) -> usize {
|
||||
|
@ -81,6 +91,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
panic!("node_ref should not be spread across multiple elements.");
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::Cloneable {
|
||||
panic!("node_ref should not be spread across multiple elements.");
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, C, Rndr> NextAttribute<Rndr> for NodeRefAttr<E, C, Rndr>
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
view::{Position, ToTemplate},
|
||||
};
|
||||
use send_wrapper::SendWrapper;
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
use std::{borrow::Cow, marker::PhantomData, sync::Arc};
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -21,18 +21,28 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Property<K, P, R>
|
||||
where
|
||||
K: AsRef<str>,
|
||||
P: IntoProperty<R>,
|
||||
R: DomRenderer,
|
||||
{
|
||||
#[derive(Debug)]
|
||||
pub struct Property<K, P, R> {
|
||||
key: K,
|
||||
// property values will only be accessed in the browser
|
||||
value: SendWrapper<P>,
|
||||
rndr: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<K, P, R> Clone for Property<K, P, R>
|
||||
where
|
||||
K: Clone,
|
||||
P: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
key: self.key.clone(),
|
||||
value: self.value.clone(),
|
||||
rndr: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, P, R> Attribute<R> for Property<K, P, R>
|
||||
where
|
||||
K: AsRef<str> + Send,
|
||||
|
@ -43,6 +53,7 @@ where
|
|||
|
||||
type State = P::State;
|
||||
type Cloneable = Property<Arc<str>, P::Cloneable, R>;
|
||||
type CloneableOwned = Property<Arc<str>, P::CloneableOwned, R>;
|
||||
|
||||
#[inline(always)]
|
||||
fn html_len(&self) -> usize {
|
||||
|
@ -79,6 +90,14 @@ where
|
|||
rndr: self.rndr,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
Property {
|
||||
key: self.key.as_ref().into(),
|
||||
value: SendWrapper::new(self.value.take().into_cloneable_owned()),
|
||||
rndr: self.rndr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, P, R> NextAttribute<R> for Property<K, P, R>
|
||||
|
@ -116,6 +135,7 @@ where
|
|||
pub trait IntoProperty<R: DomRenderer> {
|
||||
type State;
|
||||
type Cloneable: IntoProperty<R> + Clone;
|
||||
type CloneableOwned: IntoProperty<R> + Clone + 'static;
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
|
@ -128,6 +148,8 @@ pub trait IntoProperty<R: DomRenderer> {
|
|||
fn rebuild(self, state: &mut Self::State, key: &str);
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable;
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned;
|
||||
}
|
||||
|
||||
macro_rules! prop_type {
|
||||
|
@ -138,6 +160,7 @@ macro_rules! prop_type {
|
|||
{
|
||||
type State = (R::Element, JsValue);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
|
@ -167,6 +190,10 @@ macro_rules! prop_type {
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoProperty<R> for Option<$prop_type>
|
||||
|
@ -175,6 +202,7 @@ macro_rules! prop_type {
|
|||
{
|
||||
type State = (R::Element, JsValue);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
|
@ -210,14 +238,207 @@ macro_rules! prop_type {
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! prop_type_str {
|
||||
($prop_type:ty) => {
|
||||
impl<R> IntoProperty<R> for $prop_type
|
||||
where
|
||||
R: DomRenderer,
|
||||
{
|
||||
type State = (R::Element, JsValue);
|
||||
type Cloneable = Arc<str>;
|
||||
type CloneableOwned = Arc<str>;
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
el: &R::Element,
|
||||
key: &str,
|
||||
) -> Self::State {
|
||||
let value = JsValue::from(&*self);
|
||||
R::set_property(el, key, &value);
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
fn build(self, el: &R::Element, key: &str) -> Self::State {
|
||||
let value = JsValue::from(&*self);
|
||||
R::set_property(el, key, &value);
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, key: &str) {
|
||||
let (el, prev) = state;
|
||||
let value = JsValue::from(&*self);
|
||||
if value != *prev {
|
||||
R::set_property(el, key, &value);
|
||||
}
|
||||
*prev = value;
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
let this: &str = &*self;
|
||||
this.into()
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
let this: &str = &*self;
|
||||
this.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoProperty<R> for Option<$prop_type>
|
||||
where
|
||||
R: DomRenderer,
|
||||
{
|
||||
type State = (R::Element, JsValue);
|
||||
type Cloneable = Option<Arc<str>>;
|
||||
type CloneableOwned = Option<Arc<str>>;
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
el: &R::Element,
|
||||
key: &str,
|
||||
) -> Self::State {
|
||||
let was_some = self.is_some();
|
||||
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
|
||||
if was_some {
|
||||
R::set_property(el, key, &value);
|
||||
}
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
fn build(self, el: &R::Element, key: &str) -> Self::State {
|
||||
let was_some = self.is_some();
|
||||
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
|
||||
if was_some {
|
||||
R::set_property(el, key, &value);
|
||||
}
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, key: &str) {
|
||||
let (el, prev) = state;
|
||||
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
|
||||
if value != *prev {
|
||||
R::set_property(el, key, &value);
|
||||
}
|
||||
*prev = value;
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.map(|n| {
|
||||
let this: &str = &*n;
|
||||
this.into()
|
||||
})
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.map(|n| {
|
||||
let this: &str = &*n;
|
||||
this.into()
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<R> IntoProperty<R> for Arc<str>
|
||||
where
|
||||
R: DomRenderer,
|
||||
{
|
||||
type State = (R::Element, JsValue);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
el: &R::Element,
|
||||
key: &str,
|
||||
) -> Self::State {
|
||||
let value = JsValue::from_str(self.as_ref());
|
||||
R::set_property(el, key, &value);
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
fn build(self, el: &R::Element, key: &str) -> Self::State {
|
||||
let value = JsValue::from_str(self.as_ref());
|
||||
R::set_property(el, key, &value);
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, key: &str) {
|
||||
let (el, prev) = state;
|
||||
let value = JsValue::from_str(self.as_ref());
|
||||
if value != *prev {
|
||||
R::set_property(el, key, &value);
|
||||
}
|
||||
*prev = value;
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoProperty<R> for Option<Arc<str>>
|
||||
where
|
||||
R: DomRenderer,
|
||||
{
|
||||
type State = (R::Element, JsValue);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
el: &R::Element,
|
||||
key: &str,
|
||||
) -> Self::State {
|
||||
let was_some = self.is_some();
|
||||
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
|
||||
if was_some {
|
||||
R::set_property(el, key, &value);
|
||||
}
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
fn build(self, el: &R::Element, key: &str) -> Self::State {
|
||||
let was_some = self.is_some();
|
||||
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
|
||||
if was_some {
|
||||
R::set_property(el, key, &value);
|
||||
}
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, key: &str) {
|
||||
let (el, prev) = state;
|
||||
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
|
||||
if value != *prev {
|
||||
R::set_property(el, key, &value);
|
||||
}
|
||||
*prev = value;
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
prop_type!(JsValue);
|
||||
prop_type!(String);
|
||||
prop_type!(&String);
|
||||
prop_type!(&str);
|
||||
prop_type!(usize);
|
||||
prop_type!(u8);
|
||||
prop_type!(u16);
|
||||
|
@ -233,3 +454,8 @@ prop_type!(i128);
|
|||
prop_type!(f32);
|
||||
prop_type!(f64);
|
||||
prop_type!(bool);
|
||||
|
||||
prop_type_str!(String);
|
||||
prop_type_str!(&String);
|
||||
prop_type_str!(&str);
|
||||
prop_type_str!(Cow<'_, str>);
|
||||
|
|
|
@ -20,15 +20,24 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Style<S, R>
|
||||
where
|
||||
S: IntoStyle<R>,
|
||||
R: DomRenderer,
|
||||
{
|
||||
#[derive(Debug)]
|
||||
pub struct Style<S, R> {
|
||||
style: S,
|
||||
rndr: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<S, R> Clone for Style<S, R>
|
||||
where
|
||||
S: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
style: self.style.clone(),
|
||||
rndr: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, R> Attribute<R> for Style<S, R>
|
||||
where
|
||||
S: IntoStyle<R>,
|
||||
|
@ -38,6 +47,7 @@ where
|
|||
|
||||
type State = S::State;
|
||||
type Cloneable = Style<S::Cloneable, R>;
|
||||
type CloneableOwned = Style<S::CloneableOwned, R>;
|
||||
|
||||
// TODO
|
||||
#[inline(always)]
|
||||
|
@ -73,6 +83,13 @@ where
|
|||
rndr: self.rndr,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
Style {
|
||||
style: self.style.into_cloneable_owned(),
|
||||
rndr: self.rndr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, R> NextAttribute<R> for Style<S, R>
|
||||
|
@ -111,6 +128,7 @@ where
|
|||
pub trait IntoStyle<R: DomRenderer>: Send {
|
||||
type State;
|
||||
type Cloneable: IntoStyle<R> + Clone;
|
||||
type CloneableOwned: IntoStyle<R> + Clone + 'static;
|
||||
|
||||
fn to_html(self, style: &mut String);
|
||||
|
||||
|
@ -121,6 +139,8 @@ pub trait IntoStyle<R: DomRenderer>: Send {
|
|||
fn rebuild(self, state: &mut Self::State);
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable;
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned;
|
||||
}
|
||||
|
||||
pub trait StylePropertyValue<R: DomRenderer> {
|
||||
|
@ -143,6 +163,7 @@ where
|
|||
{
|
||||
type State = (R::Element, &'a str);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Arc<str>;
|
||||
|
||||
fn to_html(self, style: &mut String) {
|
||||
style.push_str(self);
|
||||
|
@ -169,14 +190,19 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoStyle<R> for String
|
||||
impl<R> IntoStyle<R> for Arc<str>
|
||||
where
|
||||
R: DomRenderer,
|
||||
{
|
||||
type State = (R::Element, String);
|
||||
type Cloneable = String; // TODO can do Arc<str> here I guess
|
||||
type State = (R::Element, Arc<str>);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn to_html(self, style: &mut String) {
|
||||
style.push_str(&self);
|
||||
|
@ -203,6 +229,95 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoStyle<R> for String
|
||||
where
|
||||
R: DomRenderer,
|
||||
{
|
||||
type State = (R::Element, String);
|
||||
type Cloneable = Arc<str>;
|
||||
type CloneableOwned = Arc<str>;
|
||||
|
||||
fn to_html(self, style: &mut String) {
|
||||
style.push_str(&self);
|
||||
style.push(';');
|
||||
}
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(self, el: &R::Element) -> Self::State {
|
||||
(el.clone(), self)
|
||||
}
|
||||
|
||||
fn build(self, el: &R::Element) -> Self::State {
|
||||
R::set_attribute(el, "style", &self);
|
||||
(el.clone(), self)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let (el, prev) = state;
|
||||
if self != *prev {
|
||||
R::set_attribute(el, "style", &self);
|
||||
}
|
||||
*prev = self;
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.into()
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> IntoStyle<R> for (Arc<str>, Arc<str>)
|
||||
where
|
||||
R: DomRenderer,
|
||||
{
|
||||
type State = (R::CssStyleDeclaration, Arc<str>);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn to_html(self, style: &mut String) {
|
||||
let (name, value) = self;
|
||||
style.push_str(&name);
|
||||
style.push(':');
|
||||
style.push_str(&value);
|
||||
style.push(';');
|
||||
}
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(self, el: &R::Element) -> Self::State {
|
||||
let style = R::style(el);
|
||||
(style, self.1)
|
||||
}
|
||||
|
||||
fn build(self, el: &R::Element) -> Self::State {
|
||||
let (name, value) = self;
|
||||
let style = R::style(el);
|
||||
R::set_css_property(&style, &name, &value);
|
||||
(style, value)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let (name, value) = self;
|
||||
let (style, prev) = state;
|
||||
if value != *prev {
|
||||
R::set_css_property(style, &name, &value);
|
||||
}
|
||||
*prev = value;
|
||||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R> IntoStyle<R> for (&'a str, &'a str)
|
||||
|
@ -211,6 +326,7 @@ where
|
|||
{
|
||||
type State = (R::CssStyleDeclaration, &'a str);
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = (Arc<str>, Arc<str>);
|
||||
|
||||
fn to_html(self, style: &mut String) {
|
||||
let (name, value) = self;
|
||||
|
@ -244,6 +360,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
(self.0.into(), self.1.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R> IntoStyle<R> for (&'a str, String)
|
||||
|
@ -251,7 +371,8 @@ where
|
|||
R: DomRenderer,
|
||||
{
|
||||
type State = (R::CssStyleDeclaration, String);
|
||||
type Cloneable = Self; // TODO can use Arc<str> here
|
||||
type Cloneable = (Arc<str>, Arc<str>);
|
||||
type CloneableOwned = (Arc<str>, Arc<str>);
|
||||
|
||||
fn to_html(self, style: &mut String) {
|
||||
let (name, value) = self;
|
||||
|
@ -283,7 +404,11 @@ where
|
|||
}
|
||||
|
||||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
(self.0.into(), self.1.into())
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
(self.0.into(), self.1.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,6 +420,7 @@ where
|
|||
{
|
||||
type State = ();
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn to_html(self, style: &mut String) {
|
||||
style.push_str(V);
|
||||
|
@ -316,6 +442,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
use crate::{
|
||||
html::{attribute::AttributeValue, class::IntoClass},
|
||||
hydration::Cursor,
|
||||
no_attrs,
|
||||
prelude::{Mountable, Render, RenderHtml},
|
||||
renderer::{DomRenderer, Renderer},
|
||||
view::{strings::StrState, Position, PositionState, ToTemplate},
|
||||
view::{
|
||||
add_attr::AddAnyAttr, strings::StrState, Position, PositionState,
|
||||
ToTemplate,
|
||||
},
|
||||
};
|
||||
use oco_ref::Oco;
|
||||
|
||||
|
@ -29,6 +33,8 @@ impl<R: Renderer> Render<R> for Oco<'static, str> {
|
|||
}
|
||||
}
|
||||
|
||||
no_attrs!(Oco<'static, str>);
|
||||
|
||||
impl<R> RenderHtml<R> for Oco<'static, str>
|
||||
where
|
||||
R: Renderer,
|
||||
|
|
|
@ -16,6 +16,7 @@ where
|
|||
{
|
||||
type State = RenderEffectState<C::State>;
|
||||
type Cloneable = SharedReactiveFunction<C>;
|
||||
type CloneableOwned = SharedReactiveFunction<C>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -80,6 +81,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.into_shared()
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.into_shared()
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T, R> IntoClass<R> for (&'static str, F)
|
||||
|
@ -90,6 +95,7 @@ where
|
|||
{
|
||||
type State = RenderEffectState<(R::ClassList, bool)>;
|
||||
type Cloneable = (&'static str, SharedReactiveFunction<T>);
|
||||
type CloneableOwned = (&'static str, SharedReactiveFunction<T>);
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.0.len()
|
||||
|
@ -160,6 +166,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
(self.0, self.1.into_shared())
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
(self.0, self.1.into_shared())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, T, R> IntoClass<R> for (Vec<Cow<'static, str>>, F)
|
||||
|
@ -170,6 +180,7 @@ where
|
|||
{
|
||||
type State = RenderEffectState<(R::ClassList, bool)>;
|
||||
type Cloneable = (Vec<Cow<'static, str>>, SharedReactiveFunction<T>);
|
||||
type CloneableOwned = (Vec<Cow<'static, str>>, SharedReactiveFunction<T>);
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.0.iter().map(|n| n.len()).sum()
|
||||
|
@ -251,6 +262,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
(self.0.clone(), self.1.into_shared())
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
(self.0.clone(), self.1.into_shared())
|
||||
}
|
||||
}
|
||||
|
||||
impl<G, R> IntoClass<R> for ReadGuard<String, G>
|
||||
|
@ -260,6 +275,7 @@ where
|
|||
{
|
||||
type State = <String as IntoClass<R>>::State;
|
||||
type Cloneable = Arc<str>;
|
||||
type CloneableOwned = Arc<str>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.len()
|
||||
|
@ -290,6 +306,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.as_str().into()
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.as_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<G, R> IntoClass<R> for (&'static str, ReadGuard<bool, G>)
|
||||
|
@ -299,6 +319,7 @@ where
|
|||
{
|
||||
type State = <(&'static str, bool) as IntoClass<R>>::State;
|
||||
type Cloneable = (&'static str, bool);
|
||||
type CloneableOwned = (&'static str, bool);
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.0.len()
|
||||
|
@ -338,6 +359,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
(self.0, *self.1)
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
(self.0, *self.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
//! Implements the [`Render`] and [`RenderHtml`] traits for signal guard types.
|
||||
|
||||
use crate::{
|
||||
html::attribute::Attribute,
|
||||
hydration::Cursor,
|
||||
prelude::RenderHtml,
|
||||
renderer::{CastFrom, Renderer},
|
||||
view::{
|
||||
strings::StrState, Mountable, Position, PositionState, Render,
|
||||
ToTemplate,
|
||||
add_attr::AddAnyAttr, strings::StrState, Mountable, Position,
|
||||
PositionState, Render, ToTemplate,
|
||||
},
|
||||
};
|
||||
use reactive_graph::signal::guards::ReadGuard;
|
||||
|
@ -72,6 +73,26 @@ macro_rules! render_primitive {
|
|||
}
|
||||
}
|
||||
|
||||
impl<G, R> AddAnyAttr<R> for ReadGuard<$child_type, G>
|
||||
where
|
||||
R: Renderer,
|
||||
G: Deref<Target = $child_type> + Send
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> = ReadGuard<$child_type, G>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
// TODO: there is a strange compiler thing that seems to prevent us returning Self here,
|
||||
// even though we've already said that Output is always the same as Self
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<G, R> RenderHtml<R> for ReadGuard<$child_type, G>
|
||||
where
|
||||
R: Renderer,
|
||||
|
@ -218,10 +239,29 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<G, R> AddAnyAttr<R> for ReadGuard<String, G>
|
||||
where
|
||||
G: Deref<Target = String> + Send,
|
||||
R: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> = ReadGuard<String, G>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
// TODO: there is a strange compiler thing that seems to prevent us returning Self here,
|
||||
// even though we've already said that Output is always the same as Self
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<G, R> RenderHtml<R> for ReadGuard<String, G>
|
||||
where
|
||||
R: Renderer,
|
||||
|
||||
G: Deref<Target = String> + Send,
|
||||
{
|
||||
type AsyncOutput = Self;
|
||||
|
|
|
@ -14,6 +14,7 @@ where
|
|||
{
|
||||
type State = RenderEffect<V::State>;
|
||||
type Cloneable = SharedReactiveFunction<V>;
|
||||
type CloneableOwned = SharedReactiveFunction<V>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -60,6 +61,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.into_shared()
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.into_shared()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
|
|
|
@ -23,7 +23,7 @@ pub use owned::*;
|
|||
|
||||
impl<F, V> ToTemplate for F
|
||||
where
|
||||
F: FnMut() -> V,
|
||||
F: ReactiveFunction<Output = V>,
|
||||
V: ToTemplate,
|
||||
{
|
||||
const TEMPLATE: &'static str = V::TEMPLATE;
|
||||
|
@ -42,7 +42,7 @@ where
|
|||
|
||||
impl<F, V, R> Render<R> for F
|
||||
where
|
||||
F: FnMut() -> V + 'static,
|
||||
F: ReactiveFunction<Output = V>,
|
||||
V: Render<R>,
|
||||
V::State: 'static,
|
||||
R: Renderer,
|
||||
|
@ -52,7 +52,7 @@ where
|
|||
#[track_caller]
|
||||
fn build(mut self) -> Self::State {
|
||||
RenderEffect::new(move |prev| {
|
||||
let value = self();
|
||||
let value = self.invoke();
|
||||
if let Some(mut state) = prev {
|
||||
value.rebuild(&mut state);
|
||||
state
|
||||
|
@ -146,7 +146,7 @@ where
|
|||
|
||||
impl<F, V, R> RenderHtml<R> for F
|
||||
where
|
||||
F: FnMut() -> V + Send + 'static,
|
||||
F: ReactiveFunction<Output = V>,
|
||||
V: RenderHtml<R>,
|
||||
V::State: 'static,
|
||||
|
||||
|
@ -157,7 +157,7 @@ where
|
|||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
async fn resolve(mut self) -> Self::AsyncOutput {
|
||||
self().resolve().await
|
||||
self.invoke().resolve().await
|
||||
}
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
|
@ -165,7 +165,7 @@ where
|
|||
}
|
||||
|
||||
fn to_html_with_buf(mut self, buf: &mut String, position: &mut Position) {
|
||||
let value = self();
|
||||
let value = self.invoke();
|
||||
value.to_html_with_buf(buf, position)
|
||||
}
|
||||
|
||||
|
@ -176,7 +176,7 @@ where
|
|||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
let value = self();
|
||||
let value = self.invoke();
|
||||
value.to_html_async_with_buf::<OUT_OF_ORDER>(buf, position);
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ where
|
|||
let cursor = cursor.clone();
|
||||
let position = position.clone();
|
||||
RenderEffect::new(move |prev| {
|
||||
let value = self();
|
||||
let value = self.invoke();
|
||||
if let Some(mut state) = prev {
|
||||
value.rebuild(&mut state);
|
||||
state
|
||||
|
@ -202,13 +202,12 @@ where
|
|||
|
||||
impl<F, V, R> AddAnyAttr<R> for F
|
||||
where
|
||||
F: FnMut() -> V + Send + 'static,
|
||||
V: RenderHtml<R>,
|
||||
V::State: 'static,
|
||||
|
||||
F: ReactiveFunction<Output = V>,
|
||||
V: AddAnyAttr<R>,
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> = Self;
|
||||
type Output<SomeNewAttr: Attribute<R>> =
|
||||
SharedReactiveFunction<V::Output<SomeNewAttr>>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
self,
|
||||
|
@ -217,17 +216,9 @@ where
|
|||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
self
|
||||
}
|
||||
|
||||
fn add_any_attr_by_ref<NewAttr: Attribute<R>>(
|
||||
self,
|
||||
attr: &NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
self
|
||||
/*let attr = attr.into_cloneable_owned();
|
||||
Arc::new(Mutex::new(move || self.invoke().add_any_attr(attr.clone())));*/
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,6 +295,7 @@ where
|
|||
{
|
||||
type State = RenderEffectState<V::State>;
|
||||
type Cloneable = SharedReactiveFunction<V>;
|
||||
type CloneableOwned = SharedReactiveFunction<V>;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
0
|
||||
|
@ -365,6 +357,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.into_shared()
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.into_shared()
|
||||
}
|
||||
}
|
||||
|
||||
pub type SharedReactiveFunction<T> = Arc<Mutex<dyn FnMut() -> T + Send>>;
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::{
|
||||
html::attribute::Attribute,
|
||||
hydration::Cursor,
|
||||
prelude::Mountable,
|
||||
renderer::Renderer,
|
||||
ssr::StreamBuilder,
|
||||
view::{Position, PositionState, Render, RenderHtml},
|
||||
view::{add_attr::AddAnyAttr, Position, PositionState, Render, RenderHtml},
|
||||
};
|
||||
use reactive_graph::owner::Owner;
|
||||
use std::marker::PhantomData;
|
||||
|
@ -81,6 +82,30 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, R> AddAnyAttr<R> for OwnedView<T, R>
|
||||
where
|
||||
T: AddAnyAttr<R>,
|
||||
R: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> =
|
||||
OwnedView<T::Output<SomeNewAttr>, R>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
let OwnedView { owner, view, rndr } = self;
|
||||
OwnedView {
|
||||
owner,
|
||||
view: view.add_any_attr(attr),
|
||||
rndr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R> RenderHtml<R> for OwnedView<T, R>
|
||||
where
|
||||
T: RenderHtml<R>,
|
||||
|
|
|
@ -15,6 +15,7 @@ where
|
|||
{
|
||||
type State = RenderEffect<V::State>;
|
||||
type Cloneable = SharedReactiveFunction<V>;
|
||||
type CloneableOwned = SharedReactiveFunction<V>;
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
mut self,
|
||||
|
@ -63,6 +64,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.into_shared()
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.into_shared()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
|
|
|
@ -15,6 +15,7 @@ where
|
|||
{
|
||||
type State = RenderEffect<(R::CssStyleDeclaration, Cow<'static, str>)>;
|
||||
type Cloneable = (&'static str, SharedReactiveFunction<S>);
|
||||
type CloneableOwned = (&'static str, SharedReactiveFunction<S>);
|
||||
|
||||
fn to_html(self, style: &mut String) {
|
||||
let (name, mut f) = self;
|
||||
|
@ -84,6 +85,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
(self.0, self.1.into_shared())
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
(self.0, self.1.into_shared())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, C, R> IntoStyle<R> for F
|
||||
|
@ -95,6 +100,7 @@ where
|
|||
{
|
||||
type State = RenderEffect<C::State>;
|
||||
type Cloneable = SharedReactiveFunction<C>;
|
||||
type CloneableOwned = SharedReactiveFunction<C>;
|
||||
|
||||
fn to_html(mut self, style: &mut String) {
|
||||
let value = self.invoke();
|
||||
|
@ -136,6 +142,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self.into_shared()
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self.into_shared()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
|
@ -150,6 +160,7 @@ mod stable {
|
|||
{
|
||||
type State = RenderEffect<C::State>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn to_html(self, style: &mut String) {
|
||||
let value = self.get();
|
||||
|
@ -174,6 +185,10 @@ mod stable {
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, S> IntoStyle<R> for (&'static str, $sig<S>)
|
||||
|
@ -184,6 +199,7 @@ mod stable {
|
|||
type State =
|
||||
RenderEffect<(R::CssStyleDeclaration, Cow<'static, str>)>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn to_html(self, style: &mut String) {
|
||||
IntoStyle::<R>::to_html(
|
||||
|
@ -213,6 +229,10 @@ mod stable {
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -227,6 +247,7 @@ mod stable {
|
|||
{
|
||||
type State = RenderEffect<C::State>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn to_html(self, style: &mut String) {
|
||||
let value = self.get();
|
||||
|
@ -251,6 +272,10 @@ mod stable {
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, S> IntoStyle<R> for (&'static str, $sig<S>)
|
||||
|
@ -261,6 +286,7 @@ mod stable {
|
|||
type State =
|
||||
RenderEffect<(R::CssStyleDeclaration, Cow<'static, str>)>;
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
fn to_html(self, style: &mut String) {
|
||||
IntoStyle::<R>::to_html(
|
||||
|
@ -290,6 +316,10 @@ mod stable {
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ pub mod sledgehammer;
|
|||
/// By default, this is implemented for the Document Object Model (DOM) in a Web
|
||||
/// browser, but implementing this trait for some other platform allows you to use
|
||||
/// the library to render any tree-based UI.
|
||||
pub trait Renderer: Send + Sized + Debug {
|
||||
pub trait Renderer: Send + Sized + Debug + 'static {
|
||||
/// The basic type of node in the view tree.
|
||||
type Node: Mountable<Self> + Clone + 'static;
|
||||
/// A visible element in the view tree.
|
||||
|
|
|
@ -20,11 +20,24 @@ where
|
|||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>;
|
||||
|
||||
fn add_any_attr_by_ref<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: &NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! no_attrs {
|
||||
($ty_name:ty) => {
|
||||
impl<'a, R> crate::view::add_attr::AddAnyAttr<R> for $ty_name
|
||||
where
|
||||
R: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: crate::html::attribute::Attribute<R>> =
|
||||
$ty_name;
|
||||
|
||||
fn add_any_attr<NewAttr: crate::html::attribute::Attribute<R>>(
|
||||
self,
|
||||
_attr: NewAttr,
|
||||
) -> Self::Output<NewAttr> {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
use super::{Mountable, Position, PositionState, Render, RenderHtml};
|
||||
use crate::{hydration::Cursor, renderer::Renderer, ssr::StreamBuilder};
|
||||
use super::{
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::Attribute, hydration::Cursor, renderer::Renderer,
|
||||
ssr::StreamBuilder,
|
||||
};
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
fmt::Debug,
|
||||
|
@ -246,6 +252,23 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<R> AddAnyAttr<R> for AnyView<R>
|
||||
where
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> = Self;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> RenderHtml<R> for AnyView<R>
|
||||
where
|
||||
R: Renderer + 'static,
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
use super::{Mountable, Position, PositionState, Render, RenderHtml};
|
||||
use crate::{hydration::Cursor, renderer::Renderer, ssr::StreamBuilder};
|
||||
use super::{
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::Attribute, hydration::Cursor, renderer::Renderer,
|
||||
ssr::StreamBuilder,
|
||||
};
|
||||
use either_of::*;
|
||||
|
||||
pub struct EitherState<A, B, Rndr>
|
||||
|
@ -97,6 +103,31 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<A, B, Rndr> AddAnyAttr<Rndr> for Either<A, B>
|
||||
where
|
||||
A: RenderHtml<Rndr>,
|
||||
B: RenderHtml<Rndr>,
|
||||
Rndr: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> = Either<
|
||||
<A as AddAnyAttr<Rndr>>::Output<SomeNewAttr>,
|
||||
<B as AddAnyAttr<Rndr>>::Output<SomeNewAttr>,
|
||||
>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
match self {
|
||||
Either::Left(i) => Either::Left(i.add_any_attr(attr)),
|
||||
Either::Right(i) => Either::Right(i.add_any_attr(attr)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fn max_usize(vals: &[usize]) -> usize {
|
||||
let mut max = 0;
|
||||
let len = vals.len();
|
||||
|
@ -261,6 +292,28 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<A, B, Rndr> AddAnyAttr<Rndr> for EitherKeepAlive<A, B>
|
||||
where
|
||||
A: RenderHtml<Rndr>,
|
||||
B: RenderHtml<Rndr>,
|
||||
Rndr: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> = EitherKeepAlive<
|
||||
<A as AddAnyAttr<Rndr>>::Output<SomeNewAttr>,
|
||||
<B as AddAnyAttr<Rndr>>::Output<SomeNewAttr>,
|
||||
>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, Rndr> RenderHtml<Rndr> for EitherKeepAlive<A, B>
|
||||
where
|
||||
A: RenderHtml<Rndr>,
|
||||
|
@ -449,6 +502,28 @@ macro_rules! tuples {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Rndr, $($ty,)*> AddAnyAttr<Rndr> for [<EitherOf $num>]<$($ty,)*>
|
||||
where
|
||||
$($ty: RenderHtml<Rndr>,)*
|
||||
Rndr: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> = [<EitherOf $num>]<
|
||||
$(<$ty as AddAnyAttr<Rndr>>::Output<SomeNewAttr>,)*
|
||||
>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
match self {
|
||||
$([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.add_any_attr(attr)),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rndr, $($ty,)*> RenderHtml<Rndr> for [<EitherOf $num>]<$($ty,)*>
|
||||
where
|
||||
$($ty: RenderHtml<Rndr>,)*
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use super::{Position, PositionState, RenderHtml};
|
||||
use super::{add_attr::AddAnyAttr, Position, PositionState, RenderHtml};
|
||||
use crate::{
|
||||
html::attribute::Attribute,
|
||||
hydration::Cursor,
|
||||
ssr::StreamBuilder,
|
||||
view::{Mountable, Render, Renderer},
|
||||
|
@ -112,6 +113,26 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<R, T, E> AddAnyAttr<R> for Result<T, E>
|
||||
where
|
||||
T: AddAnyAttr<R>,
|
||||
R: Renderer,
|
||||
E: Into<AnyError> + Send + 'static,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> =
|
||||
Result<<T as AddAnyAttr<R>>::Output<SomeNewAttr>, E>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, T, E> RenderHtml<R> for Result<T, E>
|
||||
where
|
||||
T: RenderHtml<R>,
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
use super::{Mountable, Position, PositionState, Render, RenderHtml};
|
||||
use crate::{hydration::Cursor, renderer::Renderer, ssr::StreamBuilder};
|
||||
use super::{
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::Attribute, hydration::Cursor, renderer::Renderer,
|
||||
ssr::StreamBuilder,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
|
||||
impl<T, R> Render<R> for Option<T>
|
||||
|
@ -39,6 +45,25 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, R> AddAnyAttr<R> for Option<T>
|
||||
where
|
||||
T: AddAnyAttr<R>,
|
||||
R: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> =
|
||||
Option<<T as AddAnyAttr<R>>::Output<SomeNewAttr>>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
self.map(|n| n.add_any_attr(attr))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R> RenderHtml<R> for Option<T>
|
||||
where
|
||||
T: RenderHtml<R>,
|
||||
|
@ -250,6 +275,28 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, R> AddAnyAttr<R> for Vec<T>
|
||||
where
|
||||
T: AddAnyAttr<R>,
|
||||
R: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> =
|
||||
Vec<<T as AddAnyAttr<R>>::Output<SomeNewAttr::Cloneable>>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
let attr = attr.into_cloneable();
|
||||
self.into_iter()
|
||||
.map(|n| n.add_any_attr(attr.clone()))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R> RenderHtml<R> for Vec<T>
|
||||
where
|
||||
T: RenderHtml<R>,
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
use super::{Mountable, Position, PositionState, Render, RenderHtml};
|
||||
use super::{
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::Attribute,
|
||||
hydration::Cursor,
|
||||
renderer::{CastFrom, Renderer},
|
||||
ssr::StreamBuilder,
|
||||
|
@ -40,7 +44,6 @@ where
|
|||
I: IntoIterator<Item = T>,
|
||||
K: Eq + Hash + 'static,
|
||||
KF: Fn(&T) -> K,
|
||||
V: Render<Rndr>,
|
||||
VF: Fn(T) -> V,
|
||||
Rndr: Renderer,
|
||||
{
|
||||
|
@ -128,14 +131,68 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, I, K, KF, VF, V, Rndr> RenderHtml<Rndr>
|
||||
impl<T, I, K, KF, VF, V, Rndr> AddAnyAttr<Rndr>
|
||||
for Keyed<T, I, K, KF, VF, V, Rndr>
|
||||
where
|
||||
I: IntoIterator<Item = T> + Send,
|
||||
K: Eq + Hash + 'static,
|
||||
KF: Fn(&T) -> K + Send,
|
||||
V: RenderHtml<Rndr>,
|
||||
VF: Fn(T) -> V + Send,
|
||||
V: 'static,
|
||||
VF: Fn(T) -> V + Send + 'static,
|
||||
T: 'static,
|
||||
Rndr: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> = Keyed<
|
||||
T,
|
||||
I,
|
||||
K,
|
||||
KF,
|
||||
Box<
|
||||
dyn Fn(
|
||||
T,
|
||||
) -> <V as AddAnyAttr<Rndr>>::Output<
|
||||
SomeNewAttr::CloneableOwned,
|
||||
> + Send,
|
||||
>,
|
||||
V::Output<SomeNewAttr::CloneableOwned>,
|
||||
Rndr,
|
||||
>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
let Keyed {
|
||||
items,
|
||||
key_fn,
|
||||
view_fn,
|
||||
rndr,
|
||||
} = self;
|
||||
let attr = attr.into_cloneable_owned();
|
||||
Keyed {
|
||||
items,
|
||||
key_fn,
|
||||
view_fn: Box::new(move |item| {
|
||||
view_fn(item).add_any_attr(attr.clone())
|
||||
}),
|
||||
rndr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I, K, KF, VF, V, Rndr> RenderHtml<Rndr>
|
||||
for Keyed<T, I, K, KF, VF, V, Rndr>
|
||||
where
|
||||
I: IntoIterator<Item = T> + Send,
|
||||
K: Eq + Hash + 'static,
|
||||
KF: Fn(&T) -> K + Send,
|
||||
V: RenderHtml<Rndr> + 'static,
|
||||
VF: Fn(T) -> V + Send + 'static,
|
||||
T: 'static,
|
||||
Rndr: Renderer,
|
||||
{
|
||||
type AsyncOutput = Vec<V::AsyncOutput>; // TODO
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use self::add_attr::AddAnyAttr;
|
||||
use crate::{hydration::Cursor, renderer::Renderer, ssr::StreamBuilder};
|
||||
use parking_lot::RwLock;
|
||||
use std::{future::Future, sync::Arc};
|
||||
|
@ -19,6 +20,12 @@ 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.
|
||||
///
|
||||
|
@ -58,7 +65,7 @@ impl std::error::Error for NeverError {}
|
|||
/// whole view piece by piece.
|
||||
pub trait RenderHtml<R: Renderer>
|
||||
where
|
||||
Self: Render<R> + Send,
|
||||
Self: Render<R> + AddAnyAttr<R> + Send,
|
||||
{
|
||||
/// The type of the view after waiting for all asynchronous data to load.
|
||||
type AsyncOutput: RenderHtml<R>;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::{Mountable, Position, PositionState, Render, RenderHtml};
|
||||
use crate::{
|
||||
hydration::Cursor,
|
||||
no_attrs,
|
||||
renderer::{CastFrom, Renderer},
|
||||
view::ToTemplate,
|
||||
};
|
||||
|
@ -62,6 +63,8 @@ macro_rules! render_primitive {
|
|||
}
|
||||
}
|
||||
|
||||
no_attrs!($child_type);
|
||||
|
||||
impl<R> RenderHtml<R> for $child_type
|
||||
where
|
||||
R: Renderer,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use super::{
|
||||
Mountable, Position, PositionState, Render, RenderHtml, ToTemplate,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml, ToTemplate,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::{Attribute, AttributeKey, AttributeValue, NextAttribute},
|
||||
|
@ -28,6 +29,12 @@ pub struct StaticAttr<K: AttributeKey, const V: &'static str> {
|
|||
ty: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<K: AttributeKey, const V: &'static str> Clone for StaticAttr<K, V> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { ty: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: AttributeKey, const V: &'static str> PartialEq for StaticAttr<K, V> {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
// by definition, two static attrs with same key and same const V are same
|
||||
|
@ -68,6 +75,7 @@ where
|
|||
|
||||
type State = ();
|
||||
type Cloneable = Self;
|
||||
type CloneableOwned = Self;
|
||||
|
||||
#[inline(always)]
|
||||
fn html_len(&self) -> usize {
|
||||
|
@ -96,6 +104,10 @@ where
|
|||
fn into_cloneable(self) -> Self::Cloneable {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, const V: &'static str, R> NextAttribute<R> for StaticAttr<K, V>
|
||||
|
@ -187,6 +199,25 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<R, const V: &'static str> AddAnyAttr<R> for Static<V>
|
||||
where
|
||||
R: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> = Static<V>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
// TODO: there is a strange compiler thing that seems to prevent us returning Self here,
|
||||
// even though we've already said that Output is always the same as Self
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const V: &'static str> ToTemplate for Static<V> {
|
||||
const TEMPLATE: &'static str = V;
|
||||
|
||||
|
|
|
@ -3,10 +3,16 @@ use super::{
|
|||
};
|
||||
use crate::{
|
||||
hydration::Cursor,
|
||||
no_attrs,
|
||||
renderer::{CastFrom, Renderer},
|
||||
};
|
||||
use std::{borrow::Cow, rc::Rc, sync::Arc};
|
||||
|
||||
no_attrs!(&'a str);
|
||||
no_attrs!(String);
|
||||
no_attrs!(Arc<str>);
|
||||
no_attrs!(Cow<'a, str>);
|
||||
|
||||
pub struct StrState<'a, R: Renderer> {
|
||||
pub node: R::Text,
|
||||
str: &'a str,
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
use super::{
|
||||
Mountable, Position, PositionState, Render, RenderHtml, ToTemplate,
|
||||
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
|
||||
RenderHtml, ToTemplate,
|
||||
};
|
||||
use crate::{
|
||||
html::attribute::Attribute, hydration::Cursor, renderer::DomRenderer,
|
||||
};
|
||||
use crate::{hydration::Cursor, renderer::DomRenderer};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct ViewTemplate<V, R>
|
||||
where
|
||||
V: Render<R> + ToTemplate,
|
||||
R: DomRenderer,
|
||||
{
|
||||
pub struct ViewTemplate<V, R> {
|
||||
view: V,
|
||||
rndr: PhantomData<R>,
|
||||
}
|
||||
|
@ -52,6 +51,25 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<V, R> AddAnyAttr<R> for ViewTemplate<V, R>
|
||||
where
|
||||
V: RenderHtml<R> + ToTemplate + 'static,
|
||||
V::State: Mountable<R>,
|
||||
R: DomRenderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<R>> = ViewTemplate<V, R>;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<R>>(
|
||||
self,
|
||||
attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<R>,
|
||||
{
|
||||
panic!("AddAnyAttr not supported on ViewTemplate");
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, R> RenderHtml<R> for ViewTemplate<V, R>
|
||||
where
|
||||
V: RenderHtml<R> + ToTemplate + 'static,
|
||||
|
|
|
@ -52,15 +52,7 @@ where
|
|||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
}
|
||||
|
||||
fn add_any_attr_by_ref<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
_attr: &NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
().add_any_attr(_attr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,16 +167,6 @@ where
|
|||
{
|
||||
(self.0.add_any_attr(attr),)
|
||||
}
|
||||
|
||||
fn add_any_attr_by_ref<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: &NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
(self.0.add_any_attr_by_ref(attr),)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_view_for_tuples {
|
||||
|
@ -343,7 +325,7 @@ macro_rules! impl_view_for_tuples {
|
|||
$($ty: AddAnyAttr<Rndr>),*,
|
||||
Rndr: Renderer,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> = ($first::Output<SomeNewAttr>, $($ty::Output<SomeNewAttr>,)*);
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> = ($first::Output<SomeNewAttr::Cloneable>, $($ty::Output<SomeNewAttr::Cloneable>,)*);
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
|
@ -352,22 +334,9 @@ macro_rules! impl_view_for_tuples {
|
|||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
self.add_any_attr_by_ref(&attr)
|
||||
}
|
||||
|
||||
fn add_any_attr_by_ref<NewAttr: Attribute<Rndr>>(
|
||||
self,
|
||||
attr: &NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml<Rndr>,
|
||||
{
|
||||
#[allow(non_snake_case)]
|
||||
let shared = attr.into_cloneable();
|
||||
let ($first, $($ty,)*) = self;
|
||||
(
|
||||
$first.add_any_attr_by_ref(&attr),
|
||||
$($ty.add_any_attr_by_ref(&attr)),*
|
||||
)
|
||||
($first.add_any_attr(shared.clone()), $($ty.add_any_attr(shared.clone()),)*)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue