mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 22:09:22 -05:00
feat(lepots-v0.7): CSSTransition and ClassList
This commit is contained in:
parent
918d924342
commit
8ccef81e44
6 changed files with 118 additions and 128 deletions
|
@ -56,7 +56,6 @@ pub fn ComponentsPage() -> impl IntoView {
|
|||
<SiteHeader/>
|
||||
<Layout has_sider=true position=LayoutPosition::Absolute attr:style="top: 64px;">
|
||||
<div class="demo-components__sider">
|
||||
{move || select_name.get()}
|
||||
<NavDrawer selected_value=select_name>
|
||||
{
|
||||
gen_menu_data().into_iter().map(|data| {
|
||||
|
|
|
@ -59,7 +59,7 @@ pub fn AccordionItem(
|
|||
<div
|
||||
class="thaw-accordion-panel"
|
||||
node_ref=panel_ref
|
||||
// style=("display: none", display.with(|d| d.is_none()))
|
||||
style=move || display.get().unwrap_or_default()
|
||||
>
|
||||
{children()}
|
||||
</div>
|
||||
|
|
|
@ -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<String>,
|
||||
#[prop(optional, into)] class: MaybeProp<String>,
|
||||
children: Children,
|
||||
) -> impl IntoView {
|
||||
|
@ -31,9 +29,13 @@ pub fn TableHeaderCell(#[prop(optional)] children: Option<Children>) -> impl Int
|
|||
view! {
|
||||
<th class="thaw-table-header-cell">
|
||||
<button class="thaw-table-header-cell__button" role="presentation">
|
||||
<OptionComp value=children let:children>
|
||||
{children()}
|
||||
</OptionComp>
|
||||
{
|
||||
if let Some(children) = children {
|
||||
Either::Left(children())
|
||||
} else {
|
||||
Either::Right(())
|
||||
}
|
||||
}
|
||||
</button>
|
||||
</th>
|
||||
}
|
||||
|
@ -61,9 +63,13 @@ pub fn TableRow(children: Children) -> impl IntoView {
|
|||
pub fn TableCell(#[prop(optional)] children: Option<Children>) -> impl IntoView {
|
||||
view! {
|
||||
<td class="thaw-table-cell">
|
||||
<OptionComp value=children let:children>
|
||||
{children()}
|
||||
</OptionComp>
|
||||
{
|
||||
if let Some(children) = children {
|
||||
Either::Left(children())
|
||||
} else {
|
||||
Either::Right(())
|
||||
}
|
||||
}
|
||||
</td>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::<EventListenerHandle>);
|
||||
let end_count = StoredValue::new(None::<usize>);
|
||||
let finish = StoredValue::new(None::<Box<dyn FnOnce() + Send + Sync>>);
|
||||
|
||||
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::<EventListenerHandle>);
|
||||
let end_count = StoredValue::new(None::<usize>);
|
||||
let finish = StoredValue::new(None::<Callback<()>>);
|
||||
|
||||
let on_end = Callback::new({
|
||||
let on_end = {
|
||||
let el = send_wrapper::SendWrapper::new(el.clone());
|
||||
move |remove: Callback<()>| {
|
||||
move |remove: Box<dyn FnOnce() + Send + Sync>| {
|
||||
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<bool>| {
|
||||
let effect = RenderEffect::new(move |prev: Option<bool>| {
|
||||
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();
|
||||
|
|
|
@ -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<HashSet<Oco<'static, str>>>,
|
||||
effects: Vec<AnySubscriber>,
|
||||
effects_oco: Vec<Arc<RenderEffect<Oco<'static, str>>>>,
|
||||
effects_option_oco: Vec<Arc<RenderEffect<Option<Oco<'static, str>>>>>,
|
||||
effects_bool: Vec<Arc<RenderEffect<bool>>>,
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 || {
|
||||
|
|
Loading…
Add table
Reference in a new issue