mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 22:09:22 -05:00
feat(leptos-v0.7): ClassList
This commit is contained in:
parent
d1909554c4
commit
918d924342
4 changed files with 143 additions and 94 deletions
|
@ -56,6 +56,7 @@ pub fn ComponentsPage() -> impl IntoView {
|
||||||
<SiteHeader/>
|
<SiteHeader/>
|
||||||
<Layout has_sider=true position=LayoutPosition::Absolute attr:style="top: 64px;">
|
<Layout has_sider=true position=LayoutPosition::Absolute attr:style="top: 64px;">
|
||||||
<div class="demo-components__sider">
|
<div class="demo-components__sider">
|
||||||
|
{move || select_name.get()}
|
||||||
<NavDrawer selected_value=select_name>
|
<NavDrawer selected_value=select_name>
|
||||||
{
|
{
|
||||||
gen_menu_data().into_iter().map(|data| {
|
gen_menu_data().into_iter().map(|data| {
|
||||||
|
|
|
@ -80,7 +80,7 @@ pub fn Icon(
|
||||||
icon_data.set(Some(icon.data.to_string()));
|
icon_data.set(Some(icon.data.to_string()));
|
||||||
});
|
});
|
||||||
|
|
||||||
view! {
|
let svg = view! {
|
||||||
<svg
|
<svg
|
||||||
class=class_list!["thaw-icon", class.map(|c| move || c.get())]
|
class=class_list!["thaw-icon", class.map(|c| move || c.get())]
|
||||||
style=move || take_signal(icon_style)
|
style=move || take_signal(icon_style)
|
||||||
|
@ -94,10 +94,12 @@ pub fn Icon(
|
||||||
stroke-width=move || take(icon_stroke_width)
|
stroke-width=move || take(icon_stroke_width)
|
||||||
stroke=move || take(icon_stroke)
|
stroke=move || take(icon_stroke)
|
||||||
fill=move || take(icon_fill)
|
fill=move || take(icon_fill)
|
||||||
inner_html=move || take(icon_data)
|
// inner_html=move || take(icon_data)
|
||||||
on:click=on_click
|
on:click=on_click
|
||||||
></svg>
|
></svg>
|
||||||
}
|
};
|
||||||
|
|
||||||
|
svg.inner_html(move || take(icon_data))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_signal(signal: RwSignal<Option<MaybeSignal<String>>>) -> String {
|
fn take_signal(signal: RwSignal<Option<MaybeSignal<String>>>) -> String {
|
||||||
|
|
|
@ -5,13 +5,15 @@ mod toast_title;
|
||||||
mod toaster;
|
mod toaster;
|
||||||
mod toaster_provider;
|
mod toaster_provider;
|
||||||
|
|
||||||
use tachys::view::any_view::AnyView;
|
|
||||||
pub use toast::*;
|
pub use toast::*;
|
||||||
|
pub use toast_body::*;
|
||||||
|
pub use toast_footer::*;
|
||||||
pub use toast_title::*;
|
pub use toast_title::*;
|
||||||
pub use toaster_provider::*;
|
pub use toaster_provider::*;
|
||||||
|
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use std::sync::mpsc::{channel, Receiver, Sender, TryIter};
|
use std::sync::mpsc::{channel, Receiver, Sender, TryIter};
|
||||||
|
use tachys::view::any_view::AnyView;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ToasterInjection {
|
pub struct ToasterInjection {
|
||||||
|
|
|
@ -1,26 +1,34 @@
|
||||||
#[cfg(not(feature = "ssr"))]
|
#[cfg(not(feature = "ssr"))]
|
||||||
use leptos::prelude::RenderEffect;
|
use leptos::prelude::RenderEffect;
|
||||||
use leptos::{
|
use leptos::{
|
||||||
|
logging::log,
|
||||||
prelude::{MaybeProp, Memo, Oco, RwSignal},
|
prelude::{MaybeProp, Memo, Oco, RwSignal},
|
||||||
reactive_graph::traits::{Get, Update, With, WithUntracked},
|
reactive_graph::{
|
||||||
|
graph::{AnySubscriber, ToAnySubscriber},
|
||||||
|
traits::{Get, Update, With, WithUntracked},
|
||||||
|
},
|
||||||
tachys::renderer::DomRenderer,
|
tachys::renderer::DomRenderer,
|
||||||
};
|
};
|
||||||
use std::collections::HashSet;
|
use std::{collections::HashSet, sync::Arc};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct ClassList(RwSignal<HashSet<Oco<'static, str>>>);
|
pub struct ClassList {
|
||||||
|
value: RwSignal<HashSet<Oco<'static, str>>>,
|
||||||
|
effects: Vec<AnySubscriber>,
|
||||||
|
effects_bool: Vec<Arc<RenderEffect<bool>>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl ClassList {
|
impl ClassList {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self(RwSignal::new(HashSet::new()))
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(self, value: impl IntoClass) -> Self {
|
pub fn add(mut self, value: impl IntoClass) -> Self {
|
||||||
let class = value.into_class();
|
let class = value.into_class();
|
||||||
match class {
|
match class {
|
||||||
Class::None => (),
|
Class::None => (),
|
||||||
Class::String(name) => {
|
Class::String(name) => {
|
||||||
self.0.update(move |set| {
|
self.value.update(move |set| {
|
||||||
set.insert(name);
|
set.insert(name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -33,22 +41,25 @@ impl ClassList {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "ssr"))]
|
#[cfg(not(feature = "ssr"))]
|
||||||
let _ = RenderEffect::new(move |old_name| {
|
{
|
||||||
let name = f();
|
let effect = RenderEffect::new(move |old_name| {
|
||||||
if let Some(old_name) = old_name {
|
let name = f();
|
||||||
if old_name != name {
|
if let Some(old_name) = old_name {
|
||||||
self.0.update(|set| {
|
if old_name != name {
|
||||||
set.remove(&old_name);
|
self.value.update(|set| {
|
||||||
|
set.remove(&old_name);
|
||||||
|
set.insert(name.clone());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.value.update(|set| {
|
||||||
set.insert(name.clone());
|
set.insert(name.clone());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
name
|
||||||
self.0.update(|set| {
|
});
|
||||||
set.insert(name.clone());
|
self.effects.push(effect.to_any_subscriber());
|
||||||
});
|
}
|
||||||
}
|
|
||||||
name
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
Class::FnOptionString(f) => {
|
Class::FnOptionString(f) => {
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
|
@ -60,33 +71,36 @@ impl ClassList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "ssr"))]
|
#[cfg(not(feature = "ssr"))]
|
||||||
let _ = RenderEffect::new(move |old_name| {
|
{
|
||||||
let name = f();
|
let effect = RenderEffect::new(move |old_name| {
|
||||||
if let Some(old_name) = old_name {
|
let name = f();
|
||||||
if old_name != name {
|
if let Some(old_name) = old_name {
|
||||||
self.0.update(|set| match (old_name, name.clone()) {
|
if old_name != name {
|
||||||
(None, Some(name)) => {
|
self.value.update(|set| match (old_name, name.clone()) {
|
||||||
set.insert(name);
|
(None, Some(name)) => {
|
||||||
}
|
set.insert(name);
|
||||||
(Some(old_name), None) => {
|
}
|
||||||
set.remove(&old_name);
|
(Some(old_name), None) => {
|
||||||
}
|
set.remove(&old_name);
|
||||||
(Some(old_name), Some(name)) => {
|
}
|
||||||
set.remove(&old_name);
|
(Some(old_name), Some(name)) => {
|
||||||
set.insert(name);
|
set.remove(&old_name);
|
||||||
}
|
set.insert(name);
|
||||||
_ => {}
|
}
|
||||||
});
|
_ => {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(name) = name.clone() {
|
||||||
|
self.value.update(|set| {
|
||||||
|
set.insert(name.clone());
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
name
|
||||||
if let Some(name) = name.clone() {
|
});
|
||||||
self.0.update(|set| {
|
self.effects.push(effect.to_any_subscriber());
|
||||||
set.insert(name.clone());
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
name
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
Class::Fn(name, f) => {
|
Class::Fn(name, f) => {
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
|
@ -99,34 +113,38 @@ impl ClassList {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "ssr"))]
|
#[cfg(not(feature = "ssr"))]
|
||||||
let _ = RenderEffect::new(move |old| {
|
{
|
||||||
let name = name.clone();
|
let effect = RenderEffect::new(move |old| {
|
||||||
let new = f();
|
let name = name.clone();
|
||||||
if old.is_none() {
|
let new = f();
|
||||||
if new {
|
log!("ClassList: {name} {new} {old:#?}");
|
||||||
self.0.update(|set| {
|
if old.is_none() {
|
||||||
set.insert(name);
|
if new {
|
||||||
|
self.value.update(|set| {
|
||||||
|
set.insert(name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if old.as_ref() != Some(&new) {
|
||||||
|
self.value.update(|set| {
|
||||||
|
if new {
|
||||||
|
set.insert(name);
|
||||||
|
} else {
|
||||||
|
set.remove(&name);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if old.as_ref() != Some(&new) {
|
new
|
||||||
self.0.update(|set| {
|
});
|
||||||
if new {
|
self.effects_bool.push(effect.into());
|
||||||
set.insert(name);
|
}
|
||||||
} else {
|
|
||||||
set.remove(&name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
new
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_class_string(self, class: &mut String) {
|
fn write_class_string(&self, class: &mut String) {
|
||||||
self.0.with(|set| {
|
self.value.with(|set| {
|
||||||
set.iter().enumerate().for_each(|(index, name)| {
|
set.iter().enumerate().for_each(|(index, name)| {
|
||||||
if name.is_empty() {
|
if name.is_empty() {
|
||||||
return;
|
return;
|
||||||
|
@ -145,12 +163,12 @@ where
|
||||||
R: DomRenderer,
|
R: DomRenderer,
|
||||||
{
|
{
|
||||||
type AsyncOutput = Self;
|
type AsyncOutput = Self;
|
||||||
type State = (R::Element, String);
|
type State = RenderEffect<(R::Element, String)>;
|
||||||
type Cloneable = Self;
|
type Cloneable = Self;
|
||||||
type CloneableOwned = Self;
|
type CloneableOwned = Self;
|
||||||
|
|
||||||
fn html_len(&self) -> usize {
|
fn html_len(&self) -> usize {
|
||||||
self.0.with_untracked(|set| {
|
self.value.with_untracked(|set| {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
set.iter().enumerate().for_each(|(index, name)| {
|
set.iter().enumerate().for_each(|(index, name)| {
|
||||||
if name.is_empty() {
|
if name.is_empty() {
|
||||||
|
@ -167,37 +185,63 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_html(self, class: &mut String) {
|
fn to_html(self, class: &mut String) {
|
||||||
self.to_class_string(class);
|
self.write_class_string(class);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hydrate<const FROM_SERVER: bool>(self, el: &R::Element) -> Self::State {
|
fn hydrate<const FROM_SERVER: bool>(self, el: &R::Element) -> Self::State {
|
||||||
let class_list = R::class_list(el);
|
let el = el.to_owned();
|
||||||
let mut class = String::new();
|
RenderEffect::new(move |prev| {
|
||||||
self.to_class_string(&mut class);
|
if let Some(_) = prev {
|
||||||
|
unreachable!()
|
||||||
if !FROM_SERVER {
|
} else {
|
||||||
R::add_class(&class_list, &class);
|
let mut class = String::new();
|
||||||
}
|
self.write_class_string(&mut class);
|
||||||
(el.clone(), class)
|
if !class.is_empty() {
|
||||||
|
if !FROM_SERVER {
|
||||||
|
R::set_attribute(&el, "class", &class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(el.clone(), class)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(self, el: &R::Element) -> Self::State {
|
fn build(self, el: &R::Element) -> Self::State {
|
||||||
let mut class = String::new();
|
let el = el.to_owned();
|
||||||
self.to_class_string(&mut class);
|
RenderEffect::new(move |prev| {
|
||||||
if !class.is_empty() {
|
if let Some(_) = prev {
|
||||||
R::set_attribute(el, "class", &class);
|
unreachable!()
|
||||||
}
|
} else {
|
||||||
(el.clone(), class)
|
let mut class = String::new();
|
||||||
|
self.write_class_string(&mut class);
|
||||||
|
if !class.is_empty() {
|
||||||
|
R::set_attribute(&el, "class", &class);
|
||||||
|
}
|
||||||
|
(el.clone(), class)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rebuild(self, state: &mut Self::State) {
|
fn rebuild(self, state: &mut Self::State) {
|
||||||
let mut class = String::new();
|
let prev = state.take_value();
|
||||||
self.to_class_string(&mut class);
|
*state = RenderEffect::new_with_value(
|
||||||
let (el, prev_class) = state;
|
move |prev| {
|
||||||
if class != *prev_class {
|
if let Some(state) = prev {
|
||||||
R::set_attribute(el, "class", &class);
|
let mut class = String::new();
|
||||||
}
|
self.write_class_string(&mut class);
|
||||||
*prev_class = class;
|
let (el, prev_class) = state;
|
||||||
|
if class != *prev_class {
|
||||||
|
R::set_attribute(&el, "class", &class);
|
||||||
|
(el, class)
|
||||||
|
} else {
|
||||||
|
(el, prev_class)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
prev,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_cloneable(self) -> Self::Cloneable {
|
fn into_cloneable(self) -> Self::Cloneable {
|
||||||
|
|
Loading…
Add table
Reference in a new issue