diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 880a940..fe36075 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -56,7 +56,6 @@ pub fn ComponentsPage() -> impl IntoView {
- {move || select_name.get()} { gen_menu_data().into_iter().map(|data| { diff --git a/thaw/src/accordion/accordion_item.rs b/thaw/src/accordion/accordion_item.rs index 1a74f83..b7d02c8 100644 --- a/thaw/src/accordion/accordion_item.rs +++ b/thaw/src/accordion/accordion_item.rs @@ -59,7 +59,7 @@ pub fn AccordionItem(
{children()}
diff --git a/thaw/src/table/mod.rs b/thaw/src/table/mod.rs index 3afeaa2..8779f78 100644 --- a/thaw/src/table/mod.rs +++ b/thaw/src/table/mod.rs @@ -1,10 +1,8 @@ -use leptos::prelude::*; -use thaw_components::OptionComp; +use leptos::{either::Either, prelude::*}; use thaw_utils::{class_list, mount_style}; #[component] pub fn Table( - #[prop(optional, into)] style: MaybeProp, #[prop(optional, into)] class: MaybeProp, children: Children, ) -> impl IntoView { @@ -31,9 +29,13 @@ pub fn TableHeaderCell(#[prop(optional)] children: Option) -> impl Int view! { } @@ -61,9 +63,13 @@ pub fn TableRow(children: Children) -> impl IntoView { pub fn TableCell(#[prop(optional)] children: Option) -> impl IntoView { view! { - - {children()} - + { + if let Some(children) = children { + Either::Left(children()) + } else { + Either::Right(()) + } + } } } diff --git a/thaw_components/src/css_transition/mod.rs b/thaw_components/src/css_transition/mod.rs index 3834386..b58e9d9 100644 --- a/thaw_components/src/css_transition/mod.rs +++ b/thaw_components/src/css_transition/mod.rs @@ -27,6 +27,10 @@ where IV: IntoView + 'static, { let display = RwSignal::new((!show.get_untracked()).then_some("display: none;")); + let next_frame = NextFrame::new(); + let end_handle = StoredValue::new(None::); + let end_count = StoredValue::new(None::); + let finish = StoredValue::new(None::>); Effect::new(move |_| { let target_ref = node_ref.get(); @@ -35,27 +39,23 @@ where }; let class_list = el.class_list(); - let next_frame = NextFrame::use_(); - let end_handle = StoredValue::new(None::); - let end_count = StoredValue::new(None::); - let finish = StoredValue::new(None::>); - let on_end = Callback::new({ + let on_end = { let el = send_wrapper::SendWrapper::new(el.clone()); - move |remove: Callback<()>| { + move |remove: Box| { let Some(CSSTransitionInfo { types, prop_count, timeout, }) = get_transition_info(&el) else { - remove.call(()); + remove(); return; }; - finish.set_value(Some(Callback::new(move |_| { + finish.set_value(Some(Box::new(move || { end_count.set_value(None); - remove.call(()); + remove(); end_handle.update_value(|h| { h.take().map(|h| { h.remove(); @@ -65,9 +65,9 @@ where set_timeout( move || { - finish.try_update_value(|v| { - v.take().map(|f| f.call(())); - }); + if let Some(Some(f)) = finish.try_update_value(|f| f.take()) { + f(); + } }, Duration::from_millis(timeout + 1), ); @@ -86,9 +86,9 @@ where }; *v >= prop_count }) { - finish.update_value(|v| { - v.take().map(|f| f.call(())); - }); + if let Some(Some(f)) = finish.try_update_value(|f| f.take()) { + f(); + } } }; let handle = match types { @@ -105,97 +105,16 @@ where }; end_handle.set_value(Some(handle)); } - }); + }; let on_finish = move || { - finish.update_value(|v| { - v.take().map(|f| f.call(())); - }); - }; - - let on_enter_fn = { - let class_list = class_list.clone(); - let class_list = send_wrapper::SendWrapper::new(class_list); - let on_before_enter = on_before_enter.clone(); - let on_after_enter = on_after_enter.clone(); - let on_enter = on_enter.clone(); - let on_end = on_end.clone(); - Callback::new(move |name: String| { - if let Some(on_before_enter) = on_before_enter.as_ref() { - on_before_enter.call(()); - } - let enter_from = format!("{name}-enter-from"); - let enter_active = format!("{name}-enter-active"); - let enter_to = format!("{name}-enter-to"); - - let _ = class_list.add_2(&enter_from, &enter_active); - display.set(None); - - let class_list = class_list.clone(); - let on_after_enter = on_after_enter.clone(); - let on_end = on_end.clone(); - let on_enter = on_enter.clone(); - next_frame.run(move || { - let _ = class_list.remove_1(&enter_from); - let _ = class_list.add_1(&enter_to); - - let remove = Callback::new(move |_| { - let _ = class_list.remove_2(&enter_active, &enter_to); - if let Some(on_after_enter) = on_after_enter.as_ref() { - on_after_enter.call(()); - } - }); - on_end.call(remove); - - if let Some(on_enter) = on_enter { - on_enter.call(()); - } - }); - }) - }; - - let on_leave_fn = { - let class_list = class_list.clone(); - let class_list = send_wrapper::SendWrapper::new(class_list); - let on_before_leave = on_before_leave.clone(); - let on_after_leave = on_after_leave.clone(); - let on_leave = on_leave.clone(); - let on_end = on_end.clone(); - Callback::new(move |name: String| { - if let Some(on_before_leave) = on_before_leave.as_ref() { - on_before_leave.call(()); - } - let leave_from = format!("{name}-leave-from"); - let leave_active = format!("{name}-leave-active"); - let leave_to = format!("{name}-leave-to"); - - let _ = class_list.add_2(&leave_from, &leave_active); - - let class_list = class_list.clone(); - let on_after_leave = on_after_leave.clone(); - let on_end = on_end.clone(); - let on_leave = on_leave.clone(); - next_frame.run(move || { - let _ = class_list.remove_1(&leave_from); - let _ = class_list.add_1(&leave_to); - - let remove = Callback::new(move |_| { - let _ = class_list.remove_2(&leave_active, &leave_to); - display.set(Some("display: none;")); - if let Some(on_after_leave) = on_after_leave.as_ref() { - on_after_leave.call(()); - } - }); - on_end.call(remove); - if let Some(on_leave) = on_leave { - on_leave.call(()); - } - }); - }) + if let Some(Some(f)) = finish.try_update_value(|f| f.take()) { + f(); + } }; let name = name.clone(); - let _ = RenderEffect::new(move |prev: Option| { + let effect = RenderEffect::new(move |prev: Option| { let show = show.get(); let prev = if let Some(prev) = prev { prev @@ -209,16 +128,80 @@ where if show && !prev { on_finish(); - on_enter_fn.call(name); + { + // on_enter + if let Some(on_before_enter) = on_before_enter.as_ref() { + on_before_enter.call(()); + } + let enter_from = format!("{name}-enter-from"); + let enter_active = format!("{name}-enter-active"); + let enter_to = format!("{name}-enter-to"); + + let _ = class_list.add_2(&enter_from, &enter_active); + display.set(None); + + let class_list = class_list.clone(); + let on_end = on_end.clone(); + next_frame.run(move || { + let _ = class_list.remove_1(&enter_from); + let _ = class_list.add_1(&enter_to); + + let class_list = send_wrapper::SendWrapper::new(class_list); + let remove = Box::new(move || { + let _ = class_list.remove_2(&enter_active, &enter_to); + if let Some(on_after_enter) = on_after_enter.as_ref() { + on_after_enter.call(()); + } + }); + on_end(remove); + + if let Some(on_enter) = on_enter.as_ref() { + on_enter.call(()); + } + }); + } } else if !show && prev { on_finish(); - on_leave_fn.call(name); + { + // on_leave + if let Some(on_before_leave) = on_before_leave.as_ref() { + on_before_leave.call(()); + } + let leave_from = format!("{name}-leave-from"); + let leave_active = format!("{name}-leave-active"); + let leave_to = format!("{name}-leave-to"); + + let _ = class_list.add_2(&leave_from, &leave_active); + + let class_list = class_list.clone(); + let on_after_leave = on_after_leave.clone(); + let on_end = on_end.clone(); + let on_leave = on_leave.clone(); + next_frame.run(move || { + let _ = class_list.remove_1(&leave_from); + let _ = class_list.add_1(&leave_to); + + let class_list = send_wrapper::SendWrapper::new(class_list); + let remove = Box::new(move || { + let _ = class_list.remove_2(&leave_active, &leave_to); + display.set(Some("display: none;")); + if let Some(on_after_leave) = on_after_leave.as_ref() { + on_after_leave.call(()); + } + }); + on_end(remove); + if let Some(on_leave) = on_leave { + on_leave.call(()); + } + }); + } } show }); on_cleanup(move || { + drop(effect); end_handle.update_value(|handle| { if let Some(handle) = handle.take() { handle.remove(); diff --git a/thaw_utils/src/class_list.rs b/thaw_utils/src/class_list.rs index b118654..8175e06 100644 --- a/thaw_utils/src/class_list.rs +++ b/thaw_utils/src/class_list.rs @@ -1,12 +1,8 @@ #[cfg(not(feature = "ssr"))] use leptos::prelude::RenderEffect; use leptos::{ - logging::log, prelude::{MaybeProp, Memo, Oco, RwSignal}, - reactive_graph::{ - graph::{AnySubscriber, ToAnySubscriber}, - traits::{Get, Update, With, WithUntracked}, - }, + reactive_graph::traits::{Get, Update, With, WithUntracked}, tachys::renderer::DomRenderer, }; use std::{collections::HashSet, sync::Arc}; @@ -14,7 +10,8 @@ use std::{collections::HashSet, sync::Arc}; #[derive(Clone, Default)] pub struct ClassList { value: RwSignal>>, - effects: Vec, + effects_oco: Vec>>>, + effects_option_oco: Vec>>>>, effects_bool: Vec>>, } @@ -58,7 +55,7 @@ impl ClassList { } name }); - self.effects.push(effect.to_any_subscriber()); + self.effects_oco.push(effect.into()); } } Class::FnOptionString(f) => { @@ -99,7 +96,7 @@ impl ClassList { } name }); - self.effects.push(effect.to_any_subscriber()); + self.effects_option_oco.push(effect.into()); } } Class::Fn(name, f) => { @@ -117,7 +114,6 @@ impl ClassList { let effect = RenderEffect::new(move |old| { let name = name.clone(); let new = f(); - log!("ClassList: {name} {new} {old:#?}"); if old.is_none() { if new { self.value.update(|set| { @@ -209,11 +205,17 @@ where fn build(self, el: &R::Element) -> Self::State { let el = el.to_owned(); RenderEffect::new(move |prev| { - if let Some(_) = prev { - unreachable!() + let mut class = String::new(); + self.write_class_string(&mut class); + if let Some(state) = prev { + let (el, prev_class) = state; + if class != prev_class { + R::set_attribute(&el, "class", &class); + (el, class) + } else { + (el, prev_class) + } } else { - let mut class = String::new(); - self.write_class_string(&mut class); if !class.is_empty() { R::set_attribute(&el, "class", &class); } diff --git a/thaw_utils/src/hooks/use_next_frame.rs b/thaw_utils/src/hooks/use_next_frame.rs index c2af79d..1e13781 100644 --- a/thaw_utils/src/hooks/use_next_frame.rs +++ b/thaw_utils/src/hooks/use_next_frame.rs @@ -20,7 +20,7 @@ impl Default for NextFrame { impl Copy for NextFrame {} impl NextFrame { - pub fn use_() -> Self { + pub fn new() -> Self { let next_frame = NextFrame::default(); on_cleanup(move || {