-
Notifications
You must be signed in to change notification settings - Fork 118
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add class and style interfaces (#193)
* add class interface * add style interface * remove parse style/class logic, and panic instead (in dev) * combine attributes, styles, classes into single struct * make `class` and `style` methods polymorphic * fix clippy * Update Cargo.toml Co-authored-by: Philipp Mildenberger <[email protected]> * Update crates/xilem_web/src/context.rs Co-authored-by: Philipp Mildenberger <[email protected]> * Update crates/xilem_web/src/context.rs Co-authored-by: Philipp Mildenberger <[email protected]> * Update crates/xilem_web/src/class.rs Co-authored-by: Philipp Mildenberger <[email protected]> --------- Co-authored-by: Philipp Mildenberger <[email protected]>
- Loading branch information
1 parent
072358e
commit 74bc6fc
Showing
11 changed files
with
575 additions
and
118 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
use std::{borrow::Cow, marker::PhantomData}; | ||
|
||
use xilem_core::{Id, MessageResult}; | ||
|
||
use crate::{ | ||
interfaces::{sealed::Sealed, Element}, | ||
ChangeFlags, Cx, View, ViewMarker, | ||
}; | ||
|
||
/// A trait to make the class adding functions generic over collection type | ||
pub trait IntoClasses { | ||
fn into_classes(self, classes: &mut Vec<Cow<'static, str>>); | ||
} | ||
|
||
impl IntoClasses for String { | ||
fn into_classes(self, classes: &mut Vec<Cow<'static, str>>) { | ||
classes.push(self.into()); | ||
} | ||
} | ||
|
||
impl IntoClasses for &'static str { | ||
fn into_classes(self, classes: &mut Vec<Cow<'static, str>>) { | ||
classes.push(self.into()); | ||
} | ||
} | ||
|
||
impl IntoClasses for Cow<'static, str> { | ||
fn into_classes(self, classes: &mut Vec<Cow<'static, str>>) { | ||
classes.push(self); | ||
} | ||
} | ||
|
||
impl<T> IntoClasses for Option<T> | ||
where | ||
T: IntoClasses, | ||
{ | ||
fn into_classes(self, classes: &mut Vec<Cow<'static, str>>) { | ||
if let Some(t) = self { | ||
t.into_classes(classes); | ||
} | ||
} | ||
} | ||
|
||
impl<T> IntoClasses for Vec<T> | ||
where | ||
T: IntoClasses, | ||
{ | ||
fn into_classes(self, classes: &mut Vec<Cow<'static, str>>) { | ||
for itm in self { | ||
itm.into_classes(classes); | ||
} | ||
} | ||
} | ||
|
||
macro_rules! impl_tuple_intoclasses { | ||
($($name:ident : $type:ident),* $(,)?) => { | ||
impl<$($type),*> IntoClasses for ($($type,)*) | ||
where | ||
$($type: IntoClasses),* | ||
{ | ||
#[allow(unused_variables)] | ||
fn into_classes(self, classes: &mut Vec<Cow<'static, str>>) { | ||
let ($($name,)*) = self; | ||
$( | ||
$name.into_classes(classes); | ||
)* | ||
} | ||
} | ||
}; | ||
} | ||
|
||
impl_tuple_intoclasses!(); | ||
impl_tuple_intoclasses!(t1: T1); | ||
impl_tuple_intoclasses!(t1: T1, t2: T2); | ||
impl_tuple_intoclasses!(t1: T1, t2: T2, t3: T3); | ||
impl_tuple_intoclasses!(t1: T1, t2: T2, t3: T3, t4: T4); | ||
|
||
/// Applies a class to the underlying element. | ||
pub struct Class<E, T, A> { | ||
pub(crate) element: E, | ||
pub(crate) class_names: Vec<Cow<'static, str>>, | ||
pub(crate) phantom: PhantomData<fn() -> (T, A)>, | ||
} | ||
|
||
impl<E, T, A> ViewMarker for Class<E, T, A> {} | ||
impl<E, T, A> Sealed for Class<E, T, A> {} | ||
|
||
impl<E: Element<T, A>, T, A> View<T, A> for Class<E, T, A> { | ||
type State = E::State; | ||
type Element = E::Element; | ||
|
||
fn build(&self, cx: &mut Cx) -> (Id, Self::State, Self::Element) { | ||
for class_name in &self.class_names { | ||
cx.add_class_to_element(class_name); | ||
} | ||
self.element.build(cx) | ||
} | ||
|
||
fn rebuild( | ||
&self, | ||
cx: &mut Cx, | ||
prev: &Self, | ||
id: &mut Id, | ||
state: &mut Self::State, | ||
element: &mut Self::Element, | ||
) -> ChangeFlags { | ||
for class_name in &self.class_names { | ||
cx.add_class_to_element(class_name); | ||
} | ||
self.element.rebuild(cx, &prev.element, id, state, element) | ||
} | ||
|
||
fn message( | ||
&self, | ||
id_path: &[Id], | ||
state: &mut Self::State, | ||
message: Box<dyn std::any::Any>, | ||
app_state: &mut T, | ||
) -> MessageResult<A> { | ||
self.element.message(id_path, state, message, app_state) | ||
} | ||
} | ||
|
||
crate::interfaces::impl_dom_interfaces_for_ty!(Element, Class); |
Oops, something went wrong.